resolved-dns-dnssec.c revision ca994e853c5408fcdeee66580e8b5056ad9e2c15
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 "hexdecoct.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "resolved-dns-dnssec.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "resolved-dns-packet.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "string-table.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/* Open question:
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen *
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen * How does the DNSSEC canonical form of a hostname with a label
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * containing a dot look like, the way DNS-SD does it?
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering *
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering * TODO:
a5a807e63a50314e190e9166d8a453cd8dd258e3Zbigniew Jędrzejewski-Szmek *
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering * - Make trust anchor store read additional DS+DNSKEY data from disk
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering * - wildcard zones compatibility (NSEC/NSEC3 wildcard check is missing)
39d8db043b599a7382f94bfc904d5e108af438bdLennart Poettering * - multi-label zone compatibility
39d8db043b599a7382f94bfc904d5e108af438bdLennart Poettering * - cname/dname compatibility
39d8db043b599a7382f94bfc904d5e108af438bdLennart Poettering * - per-interface DNSSEC setting
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - fix TTL for cache entries to match RRSIG TTL
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - retry on failed validation?
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - DSA 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 void initialize_libgcrypt(void) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *p;
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return;
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p = gcry_check_version("1.4.5");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_control(GCRYCTL_DISABLE_SECMEM);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringuint16_t dnssec_keytag(DnsResourceRecord *dnskey) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const uint8_t *p;
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poettering uint32_t sum;
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poettering size_t i;
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poettering
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poettering /* The algorithm from RFC 4034, Appendix B. */
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering assert(dnskey);
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering assert(dnskey->key->type == DNS_TYPE_DNSKEY);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering sum = (uint32_t) dnskey->dnskey.flags +
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p = dnskey->dnskey.key;
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart 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}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int rr_compare(const void *a, const void *b) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt 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
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(x);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(*x);
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart 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_raw(
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)))",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering n,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering e);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt 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
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int dnssec_rsa_verify(
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *hash_algorithm,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *hash, size_t hash_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceRecord *rrsig,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceRecord *dnskey) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t exponent_size, modulus_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering void *exponent, *modulus;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(hash_algorithm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(hash);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(hash_size > 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rrsig);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(dnskey);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (*(uint8_t*) dnskey->dnskey.key == 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* exponent is > 255 bytes long */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering exponent = (uint8_t*) dnskey->dnskey.key + 3;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering exponent_size =
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ((size_t) (((uint8_t*) dnskey->dnskey.key)[0]) << 8) |
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ((size_t) ((uint8_t*) dnskey->dnskey.key)[1]);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (exponent_size < 256)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (3 + exponent_size >= dnskey->dnskey.key_size)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering } else {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* exponent is <= 255 bytes long */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering exponent = (uint8_t*) dnskey->dnskey.key + 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (exponent_size <= 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (1 + exponent_size >= dnskey->dnskey.key_size)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return dnssec_rsa_verify_raw(
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering hash_algorithm,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering rrsig->rrsig.signature, rrsig->rrsig.signature_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering hash, hash_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering exponent, exponent_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering modulus, modulus_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int dnssec_ecdsa_verify_raw(
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *hash_algorithm,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *curve,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *signature_r, size_t signature_r_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *signature_s, size_t signature_s_size,
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt const void *data, size_t data_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *key, size_t key_size) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_mpi_t q = NULL, r = NULL, s = NULL;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt gcry_error_t ge;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int k;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(hash_algorithm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_mpi_scan(&r, GCRYMPI_FMT_USG, signature_r, signature_r_size, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering k = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
0014a4ad505d119c7ac4346d9d774c3f17f663a5Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature_s, signature_s_size, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering k = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_mpi_scan(&q, GCRYMPI_FMT_USG, key, key_size, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering k = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_sexp_build(&signature_sexp,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering NULL,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "(sig-val (ecdsa (r %m) (s %m)))",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering s);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ge != 0) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering k = -EIO;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering goto finish;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering }
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering ge = gcry_sexp_build(&data_sexp,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering NULL,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering "(data (flags rfc6979) (hash %s %b))",
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering hash_algorithm,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering (int) data_size,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering data);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (ge != 0) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering k = -EIO;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering goto finish;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering }
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering ge = gcry_sexp_build(&public_key_sexp,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering NULL,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering "(public-key (ecc (curve %s) (q %m)))",
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering curve,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering q);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (ge != 0) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering k = -EIO;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering goto finish;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering }
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering k = 0;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering else if (ge != 0) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering log_debug("ECDSA signature check failed: %s", gpg_strerror(ge));
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering k = -EIO;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering } else
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering k = 1;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poetteringfinish:
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (r)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_mpi_release(r);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (s)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_mpi_release(s);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (q)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_mpi_release(q);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (public_key_sexp)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_sexp_release(public_key_sexp);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (signature_sexp)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_sexp_release(signature_sexp);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (data_sexp)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_sexp_release(data_sexp);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return k;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering}
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poetteringstatic int dnssec_ecdsa_verify(
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering const char *hash_algorithm,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering int algorithm,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering const void *hash, size_t hash_size,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering DnsResourceRecord *rrsig,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering DnsResourceRecord *dnskey) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt const char *curve;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering size_t key_size;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering uint8_t *q;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering assert(hash);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering assert(hash_size);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering assert(rrsig);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering assert(dnskey);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
8d3d7072e609ef0e0fb37e1d19a29307d58146c3Michal Schmidt if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
8d3d7072e609ef0e0fb37e1d19a29307d58146c3Michal Schmidt key_size = 32;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering curve = "NIST P-256";
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering } else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering key_size = 48;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering curve = "NIST P-384";
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering } else
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return -EOPNOTSUPP;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (dnskey->dnskey.key_size != key_size * 2)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return -EINVAL;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (rrsig->rrsig.signature_size != key_size * 2)
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return -EINVAL;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering q = alloca(key_size*2 + 1);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering memcpy(q+1, dnskey->dnskey.key, key_size*2);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return dnssec_ecdsa_verify_raw(
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering hash_algorithm,
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering curve,
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering rrsig->rrsig.signature, key_size,
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering (uint8_t*) rrsig->rrsig.signature + key_size, key_size,
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering hash, hash_size,
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering q, key_size*2+1);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering}
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poetteringstatic void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering gcry_md_write(md, &v, sizeof(v));
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering}
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poetteringstatic void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering v = htobe16(v);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering gcry_md_write(md, &v, sizeof(v));
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering}
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poetteringstatic void md_add_uint32(gcry_md_hd_t md, uint32_t v) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering v = htobe32(v);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering gcry_md_write(md, &v, sizeof(v));
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering}
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poetteringstatic int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering usec_t expiration, inception, skew;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering assert(rrsig);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering assert(rrsig->key->type == DNS_TYPE_RRSIG);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (realtime == USEC_INFINITY)
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering realtime = now(CLOCK_REALTIME);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering expiration = rrsig->rrsig.expiration * USEC_PER_SEC;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering inception = rrsig->rrsig.inception * USEC_PER_SEC;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering if (inception > expiration)
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering return -EKEYREJECTED;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering /* Permit a certain amount of clock skew of 10% of the valid
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering * time range. This takes inspiration from unbound's
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering * resolver. */
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering skew = (expiration - inception) / 10;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering if (skew > SKEW_MAX)
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering skew = SKEW_MAX;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering if (inception < skew)
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering inception = 0;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering else
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering inception -= skew;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
c4147df156835513c43260a14fc9f7af177f737fLennart Poettering if (expiration + skew < expiration)
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering expiration = USEC_INFINITY;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering else
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering expiration += skew;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return realtime < inception || realtime > expiration;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering}
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int algorithm_to_gcrypt_md(uint8_t algorithm) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Translates a DNSSEC signature algorithm into a gcrypt digest identifier */
c92e531c82a9815ec349aa1bf31236b86b2d5311Lennart Poettering
c92e531c82a9815ec349aa1bf31236b86b2d5311Lennart Poettering switch (algorithm) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen case DNSSEC_ALGORITHM_RSASHA1:
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return GCRY_MD_SHA1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering case DNSSEC_ALGORITHM_RSASHA256:
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering case DNSSEC_ALGORITHM_ECDSAP256SHA256:
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return GCRY_MD_SHA256;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering case DNSSEC_ALGORITHM_ECDSAP384SHA384:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return GCRY_MD_SHA384;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering case DNSSEC_ALGORITHM_RSASHA512:
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return GCRY_MD_SHA512;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen default:
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -EOPNOTSUPP;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen}
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenint dnssec_verify_rrset(
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen DnsAnswer *a,
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen DnsResourceKey *key,
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen DnsResourceRecord *rrsig,
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen DnsResourceRecord *dnskey,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering usec_t realtime,
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering DnssecResult *result) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering size_t hash_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering void *hash;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceRecord **list, *rr;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_hd_t md = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r, md_algorithm;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t k, n = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(key);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rrsig);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(dnskey);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(result);
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
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen * assumed the RRSIG and DNSKEY match. */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (md_algorithm == -EOPNOTSUPP) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen *result = DNSSEC_UNSUPPORTED_ALGORITHM;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 0;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering }
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (md_algorithm < 0)
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return md_algorithm;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (a->n_rrs > VERIFY_RRS_MAX)
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return -E2BIG;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = dnssec_rrsig_expired(rrsig, realtime);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (r < 0)
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return r;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (r > 0) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering *result = DNSSEC_SIGNATURE_EXPIRED;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* 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);
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering if (r < 0)
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering return r;
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering if (r == 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering continue;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* We need the wire format for ordering, and digest calculation */
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering r = dns_resource_record_to_wire_format(rr, true);
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering if (r < 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering list[n++] = rr;
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering }
096b6773886bd7a0c8c97aa684b0b67dfae58355Lennart Poettering
096b6773886bd7a0c8c97aa684b0b67dfae58355Lennart Poettering if (n <= 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -ENODATA;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Bring the RRs into canonical order */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* OK, the RRs are now in canonical order. Let's calculate the digest */
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering initialize_libgcrypt();
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering hash_size = gcry_md_get_algo_dlen(md_algorithm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(hash_size > 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen gcry_md_open(&md, md_algorithm, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!md)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return -EIO;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart 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);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering md_add_uint32(md, rrsig->rrsig.expiration);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint32(md, rrsig->rrsig.inception);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen md_add_uint16(md, rrsig->rrsig.key_tag);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_write(md, wire_format_name, r);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering for (k = 0; k < n; k++) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering const char *suffix;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering size_t l;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering rr = list[k];
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering r = dns_name_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rrsig->rrsig.labels, &suffix);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (r < 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering goto finish;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (r > 0) /* This is a wildcard! */
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_write(md, (uint8_t[]) { 1, '*'}, 2);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering r = dns_name_to_wire_format(suffix, wire_format_name, sizeof(wire_format_name), true);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (r < 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering goto finish;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_write(md, wire_format_name, r);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering md_add_uint16(md, rr->key->type);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt md_add_uint16(md, rr->key->class);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering md_add_uint32(md, rrsig->rrsig.original_ttl);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering assert(rr->wire_format_rdata_offset <= rr->wire_format_size);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering l = rr->wire_format_size - rr->wire_format_rdata_offset;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering assert(l <= 0xFFFF);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering md_add_uint16(md, (uint16_t) l);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_write(md, (uint8_t*) rr->wire_format + rr->wire_format_rdata_offset, l);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering }
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering hash = gcry_md_read(md, 0);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (!hash) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering r = -EIO;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering goto finish;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering }
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering switch (rrsig->rrsig.algorithm) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering case DNSSEC_ALGORITHM_RSASHA1:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering case DNSSEC_ALGORITHM_RSASHA256:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering case DNSSEC_ALGORITHM_RSASHA512:
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt r = dnssec_rsa_verify(
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_algo_name(md_algorithm),
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering hash, hash_size,
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering rrsig,
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering dnskey);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering break;
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering case DNSSEC_ALGORITHM_ECDSAP256SHA256:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering case DNSSEC_ALGORITHM_ECDSAP384SHA384:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering r = dnssec_ecdsa_verify(
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_algo_name(md_algorithm),
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering rrsig->rrsig.algorithm,
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering hash, hash_size,
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering rrsig,
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering dnskey);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering break;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering }
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (r < 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering goto finish;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering *result = r ? DNSSEC_VALIDATED : DNSSEC_INVALID;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering r = 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poetteringfinish:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering gcry_md_close(md);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return r;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering}
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poetteringint dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering assert(rrsig);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering assert(dnskey);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering /* Checks if the specified DNSKEY RR matches the key used for
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering * the signature in the specified RRSIG RR */
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (rrsig->key->type != DNS_TYPE_RRSIG)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return -EINVAL;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnskey->key->type != DNS_TYPE_DNSKEY)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnskey->key->class != rrsig->key->class)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnskey->dnskey.protocol != 3)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnssec_keytag(dnskey) != rrsig->rrsig.key_tag)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering}
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poetteringint dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering int r;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering assert(key);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering assert(rrsig);
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (rrsig->key->type != DNS_TYPE_RRSIG)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (rrsig->key->class != key->class)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (rrsig->rrsig.type_covered != key->type)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt /* Make sure signer is a parent of the RRset */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rrsig->key), rrsig->rrsig.signer);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r <= 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering /* Make sure the owner name has at least as many labels as the "label" fields indicates. */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = dns_name_count_labels(DNS_RESOURCE_KEY_NAME(rrsig->key));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < rrsig->rrsig.labels)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 0;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
a9feff3d774eaa1cc1b59189e8f344c01e69f888Tom Gundersen return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen}
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersenint dnssec_verify_rrset_search(
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen DnsAnswer *a,
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen DnsResourceKey *key,
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen DnsAnswer *validated_dnskeys,
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen usec_t realtime,
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen DnssecResult *result) {
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen DnsResourceRecord *rrsig;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen int r;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen assert(key);
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen assert(result);
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen if (!a || a->n_rrs <= 0)
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen return -ENODATA;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek /* Iterate through each RRSIG RR. */
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek DNS_ANSWER_FOREACH(rrsig, a) {
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek DnsResourceRecord *dnskey;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek DnsAnswerFlags flags;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek /* Is this an RRSIG RR that applies to RRs matching our key? */
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek r = dnssec_key_match_rrsig(key, rrsig);
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek if (r < 0)
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek return r;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek if (r == 0)
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek continue;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek found_rrsig = true;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek /* Look for a matching key */
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek DNS_ANSWER_FOREACH_FLAGS(dnskey, flags, validated_dnskeys) {
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek DnssecResult one_result;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek continue;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek /* Is this a DNSKEY RR that matches they key of our RRSIG? */
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek r = dnssec_rrsig_match_dnskey(rrsig, dnskey);
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek if (r < 0)
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek return r;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek if (r == 0)
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek continue;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek /* Take the time here, if it isn't set yet, so
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek * that we do all validations with the same
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek * time. */
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek if (realtime == USEC_INFINITY)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering realtime = now(CLOCK_REALTIME);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Yay, we found a matching RRSIG with a matching
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen * DNSKEY, awesome. Now let's verify all entries of
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen * the RRSet against the RRSIG and DNSKEY
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * combination. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime, &one_result);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen switch (one_result) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering case DNSSEC_VALIDATED:
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering /* Yay, the RR has been validated,
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering * return immediately. */
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt *result = DNSSEC_VALIDATED;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering return 0;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering case DNSSEC_INVALID:
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt /* If the signature is invalid, let's try another
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen key and/or signature. After all they
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen key_tags and stuff are not unique, and
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen might be shared by multiple keys. */
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering found_invalid = true;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering continue;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering case DNSSEC_UNSUPPORTED_ALGORITHM:
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering /* If the key algorithm is
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering unsupported, try another
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering RRSIG/DNSKEY pair, but remember we
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering encountered this, so that we can
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering return a proper error when we
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen encounter nothing better. */
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen found_unsupported_algorithm = true;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen continue;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering case DNSSEC_SIGNATURE_EXPIRED:
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering /* If the signature is expired, try
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering another one, but remember it, so
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering that we can return this */
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering found_expired_rrsig = true;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering continue;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering default:
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen assert_not_reached("Unexpected DNSSEC validation result");
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen }
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen }
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen }
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen if (found_expired_rrsig)
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen *result = DNSSEC_SIGNATURE_EXPIRED;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen else if (found_unsupported_algorithm)
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen *result = DNSSEC_UNSUPPORTED_ALGORITHM;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen else if (found_invalid)
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen *result = DNSSEC_INVALID;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen else if (found_rrsig)
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering *result = DNSSEC_MISSING_KEY;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering else
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering *result = DNSSEC_NO_SIGNATURE;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering return 0;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering}
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poetteringint dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering DnsResourceRecord *rr;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering int r;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
a5a807e63a50314e190e9166d8a453cd8dd258e3Zbigniew Jędrzejewski-Szmek /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen DNS_ANSWER_FOREACH(rr, a) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = dnssec_key_match_rrsig(key, rr);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
4713135eae4f7b6b670a98476fe413edfa1d9f41Zbigniew Jędrzejewski-Szmek if (r > 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen size_t c = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Converts the specified hostname into DNSSEC canonicalized
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * form. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (buffer_max < 2)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOBUFS;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering for (;;) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t i;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = dns_label_unescape(&n, buffer, buffer_max);
40a1eebde6be7ac3f1885147fc24e06ad1da260cDavid Herrmann if (r < 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r == 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering break;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (r > 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int k;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* DNSSEC validation is always done on the ASCII version of the label */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering k = dns_label_apply_idna(buffer, r, buffer, buffer_max);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (k < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return k;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (k > 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = k;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (buffer_max < (size_t) r + 2)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOBUFS;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* The DNSSEC canonical form is not clear on what to
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * do with dots appearing in labels, the way DNS-SD
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * does it. Refuse it for now. */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (memchr(buffer, '.', r))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (i = 0; i < (size_t) r; i ++) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (buffer[i] >= 'A' && buffer[i] <= 'Z')
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering buffer[i] = buffer[i] - 'A' + 'a';
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering buffer[r] = '.';
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering buffer += r + 1;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering c += r + 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering buffer_max -= r + 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (c <= 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Not even a single label: this is the root domain name */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen assert(buffer_max > 2);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen buffer[0] = '.';
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering buffer[1] = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 1;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return (int) c;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringstatic int digest_to_gcrypt_md(uint8_t algorithm) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering switch (algorithm) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering case DNSSEC_DIGEST_SHA1:
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return GCRY_MD_SHA1;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering case DNSSEC_DIGEST_SHA256:
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return GCRY_MD_SHA256;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering case DNSSEC_DIGEST_SHA384:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return GCRY_MD_SHA384;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering default:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EOPNOTSUPP;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringint dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering gcry_md_hd_t md = NULL;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering size_t hash_size;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering int md_algorithm, r;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering void *result;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering assert(dnskey);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(ds);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (dnskey->key->type != DNS_TYPE_DNSKEY)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -EINVAL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (ds->key->type != DNS_TYPE_DS)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -EKEYREJECTED;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (dnskey->dnskey.protocol != 3)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -EKEYREJECTED;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (dnskey->dnskey.algorithm != ds->ds.algorithm)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return 0;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (dnssec_keytag(dnskey) != ds->ds.key_tag)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering initialize_libgcrypt();
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (md_algorithm < 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return md_algorithm;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering hash_size = gcry_md_get_algo_dlen(md_algorithm);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering assert(hash_size > 0);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ds->ds.digest_size != hash_size)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return 0;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
a5f035960006556beab51c42e6948985635e261aLennart Poettering return r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering gcry_md_open(&md, md_algorithm, 0);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (!md)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return -EIO;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering gcry_md_write(md, owner_name, r);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering md_add_uint16(md, dnskey->dnskey.flags);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering md_add_uint8(md, dnskey->dnskey.protocol);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering md_add_uint8(md, dnskey->dnskey.algorithm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering result = gcry_md_read(md, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!result) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringfinish:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_close(md);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dnssec_verify_dnskey_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering DnsResourceRecord *ds;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering DnsAnswerFlags flags;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering assert(dnskey);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (dnskey->key->type != DNS_TYPE_DNSKEY)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DNS_ANSWER_FOREACH_FLAGS(ds, flags, validated_ds) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering continue;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ds->key->type != DNS_TYPE_DS)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen continue;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (ds->key->class != dnskey->key->class)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering continue;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(ds->key));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r == 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering continue;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = dnssec_verify_dnskey(dnskey, ds);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (r < 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return r;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (r > 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringint dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering uint8_t wire_format[DNS_WIRE_FOMAT_HOSTNAME_MAX];
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering gcry_md_hd_t md = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen size_t hash_size;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen int algorithm;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering void *result;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering unsigned k;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(nsec3);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen assert(name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(ret);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (nsec3->key->type != DNS_TYPE_NSEC3)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering algorithm = digest_to_gcrypt_md(nsec3->nsec3.algorithm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (algorithm < 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return algorithm;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering initialize_libgcrypt();
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering hash_size = gcry_md_get_algo_dlen(algorithm);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering assert(hash_size > 0);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (nsec3->nsec3.next_hashed_name_size != hash_size)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -EINVAL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (r < 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return r;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering gcry_md_open(&md, algorithm, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!md)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, wire_format, r);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering result = gcry_md_read(md, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!result) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (k = 0; k < nsec3->nsec3.iterations; k++) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering uint8_t tmp[hash_size];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering memcpy(tmp, result, hash_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_reset(md);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, tmp, hash_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering result = gcry_md_read(md, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!result) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = -EIO;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto finish;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering memcpy(ret, result, hash_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = (int) hash_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringfinish:
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering gcry_md_close(md);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return r;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int nsec3_is_good(DnsResourceRecord *rr, DnsAnswerFlags flags, DnsResourceRecord *nsec3) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *a, *b;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering assert(rr);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (rr->key->type != DNS_TYPE_NSEC3)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!IN_SET(rr->nsec3.flags, 0, 1))
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!nsec3)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (nsec3 == rr) /* Shortcut */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (rr->key->class != nsec3->key->class)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (rr->nsec3.algorithm != nsec3->nsec3.algorithm)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (rr->nsec3.iterations != nsec3->nsec3.iterations)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (rr->nsec3.salt_size != nsec3->nsec3.salt_size)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (memcmp(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a = DNS_RESOURCE_KEY_NAME(rr->key);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_name_parent(&a); /* strip off hash */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r == 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering b = DNS_RESOURCE_KEY_NAME(nsec3->key);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_name_parent(&b); /* strip off hash */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r == 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return dns_name_equal(a, b);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_free_ char *next_closer_domain = NULL, *l = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering uint8_t hashed[DNSSEC_HASH_SIZE_MAX];
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering const char *suffix, *p, *pp = NULL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering DnsResourceRecord *rr, *suffix_rr;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering DnsAnswerFlags flags;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int hashed_size, r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering bool a;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(key);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(result);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering assert(authenticated);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* First step, look for the longest common suffix we find with any NSEC3 RR in the response. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering suffix = DNS_RESOURCE_KEY_NAME(key);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (;;) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DNS_ANSWER_FOREACH_FLAGS(suffix_rr, flags, answer) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_free_ char *hashed_domain = NULL, *label = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = nsec3_is_good(suffix_rr, flags, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r == 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering continue;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(suffix_rr->key), 1, suffix);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r > 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto found_suffix;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Strip one label from the front */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_name_parent(&suffix);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r == 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering break;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *result = DNSSEC_NSEC_NO_RR;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringfound_suffix:
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering p = DNS_RESOURCE_KEY_NAME(key);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering for (;;) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering _cleanup_free_ char *hashed_domain = NULL, *label = NULL;
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering hashed_size = dnssec_nsec3_hash(suffix_rr, p, hashed);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (hashed_size == -EOPNOTSUPP) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering *result = DNSSEC_NSEC_UNSUPPORTED_ALGORITHM;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (hashed_size < 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return hashed_size;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering label = base32hexmem(hashed, hashed_size, false);
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering if (!label)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOMEM;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering hashed_domain = strjoin(label, ".", suffix, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!hashed_domain)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOMEM;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = nsec3_is_good(rr, flags, suffix_rr);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r < 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return r;
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering if (r == 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering continue;
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (rr->nsec3.next_hashed_name_size != (size_t) hashed_size)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering continue;
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), hashed_domain);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r < 0)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return r;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r > 0) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering a = flags & DNS_ANSWER_AUTHENTICATED;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering goto found_closest_encloser;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering }
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering }
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering /* We didn't find the closest encloser with this name,
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering * but let's remember this domain name, it might be
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering * the next closer name */
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering pp = p;
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering /* Strip one label from the front */
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering r = dns_name_parent(&p);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r == 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering break;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *result = DNSSEC_NSEC_NO_RR;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return 0;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poetteringfound_closest_encloser:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* We found a closest encloser in 'p'; next closer is 'pp' */
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (bitmap_isset(rr->nsec3.types, DNS_TYPE_DNAME))
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return -EBADMSG;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering /* Ensure that this data is from the delegated domain
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering * (i.e. originates from the "lower" DNS server), and isn't
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering * just glue records (i.e. doesn't originate from the "upper"
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering * DNS server). */
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (bitmap_isset(rr->nsec3.types, DNS_TYPE_NS) &&
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering !bitmap_isset(rr->nsec3.types, DNS_TYPE_SOA))
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return -EBADMSG;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (!pp) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering *result = bitmap_isset(rr->nsec3.types, key->type) ? DNSSEC_NSEC_FOUND : DNSSEC_NSEC_NODATA;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering *authenticated = a;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return 0;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dnssec_nsec3_hash(rr, pp, hashed);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r != hashed_size)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EBADMSG;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering l = base32hexmem(hashed, hashed_size, false);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (!l)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOMEM;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering next_closer_domain = strjoin(l, ".", p, NULL);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (!next_closer_domain)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOMEM;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_free_ char *label = NULL, *next_hashed_domain = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering r = nsec3_is_good(rr, flags, suffix_rr);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r < 0)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return r;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r == 0)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering continue;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen label = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering if (!label)
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering return -ENOMEM;
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering next_hashed_domain = strjoin(label, ".", p, NULL);
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering if (!next_hashed_domain)
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering return -ENOMEM;
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), next_closer_domain, next_hashed_domain);
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering if (r < 0)
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering return r;
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering if (r > 0) {
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering if (rr->nsec3.flags & 1)
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering *result = DNSSEC_NSEC_OPTOUT;
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering else
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering *result = DNSSEC_NSEC_NXDOMAIN;
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering *authenticated = a && (flags & DNS_ANSWER_AUTHENTICATED);
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering return 1;
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering }
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering *result = DNSSEC_NSEC_NO_RR;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return 0;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poetteringint dnssec_test_nsec(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering DnsResourceRecord *rr;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering bool have_nsec3 = false;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering DnsAnswerFlags flags;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering int r;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering assert(key);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering assert(result);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering assert(authenticated);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering if (rr->key->class != key->class)
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering continue;
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering switch (rr->key->type) {
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering case DNS_TYPE_NSEC:
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering if (r < 0)
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering return r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r > 0) {
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering *result = bitmap_isset(rr->nsec.types, key->type) ? DNSSEC_NSEC_FOUND : DNSSEC_NSEC_NODATA;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key), rr->nsec.next_domain_name);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (r < 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return r;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (r > 0) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering *result = DNSSEC_NSEC_NXDOMAIN;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return 0;
bf3f1271e2cc0c22b11c8a805a997578dabe9191Lennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering break;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering case DNS_TYPE_NSEC3:
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering have_nsec3 = true;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering break;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (have_nsec3)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return dnssec_test_nsec3(answer, key, result, authenticated);
bf3f1271e2cc0c22b11c8a805a997578dabe9191Lennart Poettering
bf3f1271e2cc0c22b11c8a805a997578dabe9191Lennart Poettering /* No approproate NSEC RR found, report this. */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering *result = DNSSEC_NSEC_NO_RR;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringstatic const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = {
bf3f1271e2cc0c22b11c8a805a997578dabe9191Lennart Poettering [DNSSEC_NO] = "no",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_DOWNGRADE_OK] = "downgrade-ok",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_YES] = "yes",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering};
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart PoetteringDEFINE_STRING_TABLE_LOOKUP(dnssec_mode, DnssecMode);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringstatic const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_VALIDATED] = "validated",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_INVALID] = "invalid",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_SIGNATURE_EXPIRED] = "signature-expired",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_UNSUPPORTED_ALGORITHM] = "unsupported-algorithm",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_NO_SIGNATURE] = "no-signature",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_MISSING_KEY] = "missing-key",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_UNSIGNED] = "unsigned",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering [DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server",
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering};
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart PoetteringDEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering