resolved-dns-dnssec.c revision aa89931749f081be8b1f90643c81ae2860257e53
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/***
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen This file is part of systemd.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Copyright 2015 Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
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
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
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***/
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include <gcrypt.h>
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include "alloc-util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "dns-domain.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "resolved-dns-dnssec.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "resolved-dns-packet.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "string-table.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/* Open question:
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen *
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?
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering * TODO:
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering *
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 *
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define VERIFY_RRS_MAX 256
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define MAX_KEY_SIZE (32*1024)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
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
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * The DNSSEC Chain of trust:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
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 *
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Example chain:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool dnssec_algorithm_supported(int algorithm) {
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering return IN_SET(algorithm,
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering DNSSEC_ALGORITHM_RSASHA1,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1,
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering DNSSEC_ALGORITHM_RSASHA256,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DNSSEC_ALGORITHM_RSASHA512);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool dnssec_digest_supported(int digest) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return IN_SET(digest,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DNSSEC_DIGEST_SHA1,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DNSSEC_DIGEST_SHA256);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poetteringuint16_t dnssec_keytag(DnsResourceRecord *dnskey) {
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poettering const uint8_t *p;
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poettering uint32_t sum;
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poettering size_t i;
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering /* The algorithm from RFC 4034, Appendix B. */
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(dnskey);
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering assert(dnskey->key->type == DNS_TYPE_DNSKEY);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sum = (uint32_t) dnskey->dnskey.flags +
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm);
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p = dnskey->dnskey.key;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
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 Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sum += (sum >> 16) & UINT32_C(0xFFFF);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sum & UINT32_C(0xFFFF);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int rr_compare(const void *a, const void *b) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t m;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Let's order the RRs according to RFC 4034, Section 6.3 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering assert(x);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(*x);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert((*x)->wire_format);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(y);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(*y);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert((*y)->wire_format);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering m = MIN((*x)->wire_format_size, (*y)->wire_format_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = memcmp((*x)->wire_format, (*y)->wire_format, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r != 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if ((*x)->wire_format_size < (*y)->wire_format_size)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else if ((*x)->wire_format_size > (*y)->wire_format_size)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int dnssec_rsa_verify(
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *hash_algorithm,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *signature, size_t signature_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *data, size_t data_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *exponent, size_t exponent_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *modulus, size_t modulus_size) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_mpi_t n = NULL, e = NULL, s = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_error_t ge;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(hash_algorithm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_sexp_build(&signature_sexp,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering NULL,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "(sig-val (rsa (s %m)))",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering s);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_sexp_build(&data_sexp,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering NULL,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "(data (flags pkcs1) (hash %s %b))",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering hash_algorithm,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (int) data_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering data);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_sexp_build(&public_key_sexp,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering NULL,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "(public-key (rsa (n %m) (e %m)))",
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt n,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering e);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
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 r = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("RSA signature check failed: %s", gpg_strerror(ge));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering } else
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringfinish:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (e)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_mpi_release(e);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (n)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_mpi_release(n);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (s)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_mpi_release(s);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (public_key_sexp)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_sexp_release(public_key_sexp);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (signature_sexp)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_sexp_release(signature_sexp);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (data_sexp)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_sexp_release(data_sexp);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, &v, sizeof(v));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering v = htobe16(v);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, &v, sizeof(v));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void md_add_uint32(gcry_md_hd_t md, uint32_t v) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering v = htobe32(v);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, &v, sizeof(v));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering usec_t expiration, inception, skew;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rrsig);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rrsig->key->type == DNS_TYPE_RRSIG);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (realtime == USEC_INFINITY)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering realtime = now(CLOCK_REALTIME);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering expiration = rrsig->rrsig.expiration * USEC_PER_SEC;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering inception = rrsig->rrsig.inception * USEC_PER_SEC;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (inception > expiration)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EKEYREJECTED;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
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 skew = (expiration - inception) / 10;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (skew > SKEW_MAX)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering skew = SKEW_MAX;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (inception < skew)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering inception = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering inception -= skew;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (expiration + skew < expiration)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering expiration = USEC_INFINITY;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering expiration += skew;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return realtime < inception || realtime > expiration;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dnssec_verify_rrset(
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsAnswer *a,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceKey *key,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceRecord *rrsig,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceRecord *dnskey,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering usec_t realtime) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t exponent_size, modulus_size, hash_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering void *exponent, *modulus, *hash;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt DnsResourceRecord **list, *rr;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_hd_t md = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t k, n = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt assert(key);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rrsig);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(dnskey);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rrsig->key->type == DNS_TYPE_RRSIG);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(dnskey->key->type == DNS_TYPE_DNSKEY);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
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. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
0014a4ad505d119c7ac4346d9d774c3f17f663a5Lennart Poettering if (!dnssec_algorithm_supported(rrsig->rrsig.algorithm))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EOPNOTSUPP;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (a->n_rrs > VERIFY_RRS_MAX)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -E2BIG;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dnssec_rrsig_expired(rrsig, realtime);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r > 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return DNSSEC_SIGNATURE_EXPIRED;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
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
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DNS_ANSWER_FOREACH(rr, a) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_resource_key_equal(key, rr->key);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (r == 0)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering continue;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
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 if (r < 0)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return r;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering list[n++] = rr;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering }
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (n <= 0)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return -ENODATA;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering /* Bring the RRs into canonical order */
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering /* OK, the RRs are now in canonical order. Let's calculate the digest */
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering switch (rrsig->rrsig.algorithm) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering case DNSSEC_ALGORITHM_RSASHA1:
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_md_open(&md, GCRY_MD_SHA1, 0);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering hash_size = 20;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering break;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering case DNSSEC_ALGORITHM_RSASHA256:
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_md_open(&md, GCRY_MD_SHA256, 0);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering hash_size = 32;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering break;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering case DNSSEC_ALGORITHM_RSASHA512:
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_md_open(&md, GCRY_MD_SHA512, 0);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering hash_size = 64;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering break;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering default:
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering assert_not_reached("Unknown digest");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering }
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (!md)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return -EIO;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint16(md, rrsig->rrsig.type_covered);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint8(md, rrsig->rrsig.algorithm);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint8(md, rrsig->rrsig.labels);
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 md_add_uint16(md, rrsig->rrsig.key_tag);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (r < 0)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering goto finish;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_md_write(md, wire_format_name, r);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering for (k = 0; k < n; k++) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering size_t l;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering rr = list[k];
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = dns_name_to_wire_format(DNS_RESOURCE_KEY_NAME(rr->key), wire_format_name, sizeof(wire_format_name), true);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (r < 0)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering goto finish;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_md_write(md, wire_format_name, r);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint16(md, rr->key->type);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint16(md, rr->key->class);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint32(md, rrsig->rrsig.original_ttl);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
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 assert(l <= 0xFFFF);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint16(md, (uint16_t) l);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_md_write(md, (uint8_t*) rr->wire_format + rr->wire_format_rdata_offset, l);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering }
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering hash = gcry_md_read(md, 0);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (!hash) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = -EIO;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering goto finish;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering }
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (*(uint8_t*) dnskey->dnskey.key == 0) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering /* exponent is > 255 bytes long */
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering exponent = (uint8_t*) dnskey->dnskey.key + 3;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering exponent_size =
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering ((size_t) (((uint8_t*) dnskey->dnskey.key)[0]) << 8) |
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering ((size_t) ((uint8_t*) dnskey->dnskey.key)[1]);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (exponent_size < 256) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = -EINVAL;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering goto finish;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering }
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (3 + exponent_size >= dnskey->dnskey.key_size) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = -EINVAL;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering goto finish;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering }
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering } else {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering /* exponent is <= 255 bytes long */
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering exponent = (uint8_t*) dnskey->dnskey.key + 1;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (exponent_size <= 0) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = -EINVAL;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering goto finish;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering }
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (1 + exponent_size >= dnskey->dnskey.key_size) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = -EINVAL;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering goto finish;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering }
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering }
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering r = dnssec_rsa_verify(
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering gcry_md_algo_name(gcry_md_get_algo(md)),
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering rrsig->rrsig.signature, rrsig->rrsig.signature_size,
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering hash, hash_size,
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering exponent, exponent_size,
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering modulus, modulus_size);
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering if (r < 0)
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering goto finish;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering r = r ? DNSSEC_VERIFIED : DNSSEC_INVALID;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poetteringfinish:
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering gcry_md_close(md);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return r;
c4147df156835513c43260a14fc9f7af177f737fLennart Poettering}
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poetteringint dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey) {
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering assert(rrsig);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering assert(dnskey);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Checks if the specified DNSKEY RR matches the key used for
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * the signature in the specified RRSIG RR */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (rrsig->key->type != DNS_TYPE_RRSIG)
c92e531c82a9815ec349aa1bf31236b86b2d5311Lennart Poettering return -EINVAL;
c92e531c82a9815ec349aa1bf31236b86b2d5311Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (dnskey->key->type != DNS_TYPE_DNSKEY)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (dnskey->key->class != rrsig->key->class)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return 0;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (dnskey->dnskey.protocol != 3)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (dnssec_keytag(dnskey) != rrsig->rrsig.key_tag)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen}
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenint dnssec_key_match_rrsig(DnsResourceKey *key, DnsResourceRecord *rrsig) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen assert(key);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen assert(rrsig);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (rrsig->key->type != DNS_TYPE_RRSIG)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 0;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (rrsig->key->class != key->class)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return 0;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (rrsig->rrsig.type_covered != key->type)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dnssec_verify_rrset_search(
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsAnswer *a,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceKey *key,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsAnswer *validated_dnskeys,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering usec_t realtime) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering bool found_rrsig = false, found_dnskey = false;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceRecord *rrsig;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(key);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Verifies all RRs from "a" that match the key "key", against DNSKEY and DS RRs in "validated_dnskeys" */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!a || a->n_rrs <= 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -ENODATA;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Iterate through each RRSIG RR. */
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering DNS_ANSWER_FOREACH(rrsig, a) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering DnsResourceRecord *dnskey;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = dnssec_key_match_rrsig(key, rrsig);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (r < 0)
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return r;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (r == 0)
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering continue;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering found_rrsig = true;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering DNS_ANSWER_FOREACH(dnskey, validated_dnskeys) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dnssec_rrsig_match_dnskey(rrsig, dnskey);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r == 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering continue;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering found_dnskey = true;
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering /* Take the time here, if it isn't set yet, so
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering * that we do all validations with the same
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * time. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (realtime == USEC_INFINITY)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering realtime = now(CLOCK_REALTIME);
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering
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. */
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering
096b6773886bd7a0c8c97aa684b0b67dfae58355Lennart Poettering r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime);
096b6773886bd7a0c8c97aa684b0b67dfae58355Lennart Poettering if (r < 0 && r != EOPNOTSUPP)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r == DNSSEC_VERIFIED)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return DNSSEC_VERIFIED;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
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. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (found_dnskey)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return DNSSEC_INVALID;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (found_rrsig)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return DNSSEC_MISSING_KEY;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return DNSSEC_NO_SIGNATURE;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering}
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenint dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t c = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Converts the specified hostname into DNSSEC canonicalized
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering * form. */
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (buffer_max < 2)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return -ENOBUFS;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering for (;;) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering size_t i;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering r = dns_label_unescape(&n, buffer, buffer_max);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (r < 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return r;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (r == 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering break;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (r > 0) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering int k;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
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 if (k < 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return k;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (k > 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering r = k;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering }
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (buffer_max < (size_t) r + 2)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return -ENOBUFS;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
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
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (memchr(buffer, '.', r))
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return -EINVAL;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering for (i = 0; i < (size_t) r; i ++) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (buffer[i] >= 'A' && buffer[i] <= 'Z')
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering buffer[i] = buffer[i] - 'A' + 'a';
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering }
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering buffer[r] = '.';
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering buffer += r + 1;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering c += r + 1;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering buffer_max -= r + 1;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering }
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (c <= 0) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering /* Not even a single label: this is the root domain name */
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering assert(buffer_max > 2);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering buffer[0] = '.';
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering buffer[1] = 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 1;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering }
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return (int) c;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering}
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poetteringint dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_hd_t md = NULL;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering void *result;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering int r;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering assert(dnskey);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering assert(ds);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnskey->key->type != DNS_TYPE_DNSKEY)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return -EINVAL;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (ds->key->type != DNS_TYPE_DS)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return -EINVAL;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return -EKEYREJECTED;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnskey->dnskey.protocol != 3)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return -EKEYREJECTED;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnskey->dnskey.algorithm != ds->ds.algorithm)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnssec_keytag(dnskey) != ds->ds.key_tag)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (!dnssec_digest_supported(ds->ds.digest_type))
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return -EOPNOTSUPP;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering switch (ds->ds.digest_type) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering case DNSSEC_DIGEST_SHA1:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (ds->ds.digest_size != 20)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_open(&md, GCRY_MD_SHA1, 0);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering break;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering case DNSSEC_DIGEST_SHA256:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (ds->ds.digest_size != 32)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_open(&md, GCRY_MD_SHA256, 0);
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen break;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering default:
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen assert_not_reached("Unknown digest");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!md)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt if (r < 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen gcry_md_write(md, owner_name, r);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen md_add_uint16(md, dnskey->dnskey.flags);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering md_add_uint8(md, dnskey->dnskey.protocol);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen md_add_uint8(md, dnskey->dnskey.algorithm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen result = gcry_md_read(md, 0);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!result) {
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen r = -EIO;
a9feff3d774eaa1cc1b59189e8f344c01e69f888Tom Gundersen goto finish;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen }
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen r = memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersenfinish:
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen gcry_md_close(md);
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen return r;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen}
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersenstatic const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = {
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen [DNSSEC_NO] = "no",
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen [DNSSEC_TRUST] = "trust",
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen [DNSSEC_YES] = "yes",
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen};
bda2c408f8a739c19161818bcc842107f60652a2Tom GundersenDEFINE_STRING_TABLE_LOOKUP(dnssec_mode, DnssecMode);
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen