resolved-dns-dnssec.c revision 22ebb9e4a9d8802b194eccc050552d0e188af489
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering/***
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering This file is part of systemd.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering Copyright 2015 Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering (at your option) any later version.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering systemd is distributed in the hope that it will be useful, but
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering Lesser General Public License for more details.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering***/
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering#include <gcrypt.h>
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering#include "alloc-util.h"
96115cdfe0241ae9b4e7177cd3874c0a93d00b39Thomas Hindoe Paaboel Andersen#include "dns-domain.h"
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering#include "resolved-dns-dnssec.h"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering#include "resolved-dns-packet.h"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering#include "string-table.h"
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering/* Open question:
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering *
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering * How does the DNSSEC canonical form of a hostname with a label
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek * containing a dot look like, the way DNS-SD does it?
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering *
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering * TODO:
9a5cb1371b6d8b0a04bd08665bcf9b06cb40c64cZbigniew Jędrzejewski-Szmek *
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering * - Iterative validation
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering * - NSEC proof of non-existance
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering * - NSEC3 proof of non-existance
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering * - Make trust anchor store read additional DS+DNSKEY data from disk
1b9e5b126359a2a2ec37de1f94f046093abc74b8Lennart Poettering * - wildcard zones compatibility
f9ac15442e4132f00eca5495d53c17062aae13e0Lennart Poettering * - multi-label zone compatibility
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering * - DMSSEC cname/dname compatibility
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering * - per-interface DNSSEC setting
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering * - DSA support
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering * - EC support?
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering *
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering * */
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering#define VERIFY_RRS_MAX 256
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering#define MAX_KEY_SIZE (32*1024)
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering/* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering#define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering/*
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering * The DNSSEC Chain of trust:
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering *
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering * DS RRs are protected like normal RRs
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering *
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering * Example chain:
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering */
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poetteringstatic bool dnssec_algorithm_supported(int algorithm) {
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering return IN_SET(algorithm,
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering DNSSEC_ALGORITHM_RSASHA1,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering DNSSEC_ALGORITHM_RSASHA256,
821b2e792159e237a1e5a1ea4bb6ae2e55d64be5Lukas Nykryn DNSSEC_ALGORITHM_RSASHA512);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering}
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringstatic bool dnssec_digest_supported(int digest) {
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return IN_SET(digest,
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt DNSSEC_DIGEST_SHA1,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering DNSSEC_DIGEST_SHA256);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering}
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringuint16_t dnssec_keytag(DnsResourceRecord *dnskey) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering const uint8_t *p;
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering uint32_t sum;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering size_t i;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering /* The algorithm from RFC 4034, Appendix B. */
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering assert(dnskey);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering assert(dnskey->key->type == DNS_TYPE_DNSKEY);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering sum = (uint32_t) dnskey->dnskey.flags +
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering p = dnskey->dnskey.key;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering for (i = 0; i < dnskey->dnskey.key_size; i++)
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering sum += (i & 1) == 0 ? (uint32_t) p[i] << 8 : (uint32_t) p[i];
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering sum += (sum >> 16) & UINT32_C(0xFFFF);
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering return sum & UINT32_C(0xFFFF);
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering}
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poetteringstatic int rr_compare(const void *a, const void *b) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering size_t m;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering int r;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering /* Let's order the RRs according to RFC 4034, Section 6.3 */
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt assert(x);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt assert(*x);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering assert((*x)->wire_format);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering assert(y);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering assert(*y);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering assert((*y)->wire_format);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering m = MIN((*x)->wire_format_size, (*y)->wire_format_size);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt r = memcmp((*x)->wire_format, (*y)->wire_format, m);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt if (r != 0)
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering return r;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering if ((*x)->wire_format_size < (*y)->wire_format_size)
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering return -1;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering else if ((*x)->wire_format_size > (*y)->wire_format_size)
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering return 1;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return 0;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt}
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringstatic int dnssec_rsa_verify(
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering const char *hash_algorithm,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering const void *signature, size_t signature_size,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering const void *data, size_t data_size,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering const void *exponent, size_t exponent_size,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering const void *modulus, size_t modulus_size) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering gcry_mpi_t n = NULL, e = NULL, s = NULL;
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack gcry_error_t ge;
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack int r;
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt assert(hash_algorithm);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering if (ge != 0) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering r = -EIO;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering goto finish;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering }
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering if (ge != 0) {
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering r = -EIO;
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering goto finish;
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering }
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL);
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering if (ge != 0) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = -EIO;
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering goto finish;
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering }
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering ge = gcry_sexp_build(&signature_sexp,
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering NULL,
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering "(sig-val (rsa (s %m)))",
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering s);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering if (ge != 0) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering r = -EIO;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering goto finish;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering }
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering ge = gcry_sexp_build(&data_sexp,
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering NULL,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "(data (flags pkcs1) (hash %s %b))",
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering hash_algorithm,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering (int) data_size,
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering data);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering if (ge != 0) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering r = -EIO;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering goto finish;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering }
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering ge = gcry_sexp_build(&public_key_sexp,
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering NULL,
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering "(public-key (rsa (n %m) (e %m)))",
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering n,
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering e);
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if (ge != 0) {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering r = -EIO;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering goto finish;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering }
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (ge == GPG_ERR_BAD_SIGNATURE)
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering r = 0;
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering else if (ge != 0)
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering r = -EIO;
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering else
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering r = 1;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poetteringfinish:
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering if (e)
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering gcry_mpi_release(e);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering if (n)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering gcry_mpi_release(n);
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if (s)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering gcry_mpi_release(s);
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if (public_key_sexp)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering gcry_sexp_release(public_key_sexp);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (signature_sexp)
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering gcry_sexp_release(signature_sexp);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering if (data_sexp)
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering gcry_sexp_release(data_sexp);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering return r;
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering}
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sieversstatic void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers gcry_md_write(md, &v, sizeof(v));
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers}
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poetteringstatic void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering v = htobe16(v);
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering gcry_md_write(md, &v, sizeof(v));
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering}
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poetteringstatic void md_add_uint32(gcry_md_hd_t md, uint32_t v) {
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering v = htobe32(v);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering gcry_md_write(md, &v, sizeof(v));
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering}
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poetteringstatic int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt usec_t expiration, inception, skew;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering assert(rrsig);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering assert(rrsig->key->type == DNS_TYPE_RRSIG);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (realtime == USEC_INFINITY)
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering realtime = now(CLOCK_REALTIME);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers expiration = rrsig->rrsig.expiration * USEC_PER_SEC;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers inception = rrsig->rrsig.inception * USEC_PER_SEC;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (inception > expiration)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return -EKEYREJECTED;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* Permit a certain amount of clock skew of 10% of the valid
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers * time range. This takes inspiration from unbound's
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers * resolver. */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers skew = (expiration - inception) / 10;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (skew > SKEW_MAX)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers skew = SKEW_MAX;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (inception < skew)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers inception = 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers else
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers inception -= skew;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (expiration + skew < expiration)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers expiration = USEC_INFINITY;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers else
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering expiration += skew;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return realtime < inception || realtime > expiration;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering}
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poetteringint dnssec_verify_rrset(
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering DnsAnswer *a,
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering DnsResourceKey *key,
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering DnsResourceRecord *rrsig,
a0b1209c4a59754f428894e0485413542da50014Zbigniew Jędrzejewski-Szmek DnsResourceRecord *dnskey,
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering usec_t realtime) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering size_t exponent_size, modulus_size, hash_size;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering void *exponent, *modulus, *hash;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering DnsResourceRecord **list, *rr;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering gcry_md_hd_t md = NULL;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers size_t k, n = 0;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering int r;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering assert(key);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering assert(rrsig);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering assert(dnskey);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering assert(rrsig->key->type == DNS_TYPE_RRSIG);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering assert(dnskey->key->type == DNS_TYPE_DNSKEY);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering /* Verifies the the RRSet matching the specified "key" in "a",
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering * using the signature "rrsig" and the key "dnskey". It's
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering * assumed the RRSIG and DNSKEY match. */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt if (!dnssec_algorithm_supported(rrsig->rrsig.algorithm))
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return -EOPNOTSUPP;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (a->n_rrs > VERIFY_RRS_MAX)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return -E2BIG;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = dnssec_rrsig_expired(rrsig, realtime);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (r < 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return r;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (r > 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return DNSSEC_SIGNATURE_EXPIRED;
a0b1209c4a59754f428894e0485413542da50014Zbigniew Jędrzejewski-Szmek
a0b1209c4a59754f428894e0485413542da50014Zbigniew Jędrzejewski-Szmek /* Collect all relevant RRs in a single array, so that we can look at the RRset */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering list = newa(DnsResourceRecord *, a->n_rrs);
a0b1209c4a59754f428894e0485413542da50014Zbigniew Jędrzejewski-Szmek
a0b1209c4a59754f428894e0485413542da50014Zbigniew Jędrzejewski-Szmek DNS_ANSWER_FOREACH(rr, a) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = dns_resource_key_equal(key, rr->key);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (r < 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return r;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (r == 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering continue;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering /* We need the wire format for ordering, and digest calculation */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = dns_resource_record_to_wire_format(rr, true);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (r < 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return r;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering list[n++] = rr;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers }
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (n <= 0)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return -ENODATA;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* Bring the RRs into canonical order */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers qsort_safe(list, n, sizeof(DnsResourceRecord), rr_compare);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* OK, the RRs are now in canonical order. Let's calculate the digest */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers switch (rrsig->rrsig.algorithm) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers case DNSSEC_ALGORITHM_RSASHA1:
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers gcry_md_open(&md, GCRY_MD_SHA1, 0);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers hash_size = 20;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers break;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers case DNSSEC_ALGORITHM_RSASHA256:
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers gcry_md_open(&md, GCRY_MD_SHA256, 0);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers hash_size = 32;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers break;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers case DNSSEC_ALGORITHM_RSASHA512:
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers gcry_md_open(&md, GCRY_MD_SHA512, 0);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers hash_size = 64;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers break;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers default:
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers assert_not_reached("Unknown digest");
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers }
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering if (!md)
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering return -EIO;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers md_add_uint16(md, rrsig->rrsig.type_covered);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers md_add_uint8(md, rrsig->rrsig.algorithm);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers md_add_uint8(md, rrsig->rrsig.labels);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers md_add_uint32(md, rrsig->rrsig.original_ttl);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers md_add_uint32(md, rrsig->rrsig.expiration);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers md_add_uint32(md, rrsig->rrsig.inception);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers md_add_uint16(md, rrsig->rrsig.key_tag);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (r < 0)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers goto finish;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers gcry_md_write(md, wire_format_name, r);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen for (k = 0; k < n; k++) {
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen size_t l;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen rr = list[k];
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen r = dns_name_to_wire_format(DNS_RESOURCE_KEY_NAME(rr->key), wire_format_name, sizeof(wire_format_name), true);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (r < 0)
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen goto finish;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen gcry_md_write(md, wire_format_name, r);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen md_add_uint16(md, rr->key->type);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen md_add_uint16(md, rr->key->class);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen md_add_uint32(md, rrsig->rrsig.original_ttl);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen assert(rr->wire_format_rdata_offset <= rr->wire_format_size);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen l = rr->wire_format_size - rr->wire_format_rdata_offset;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen assert(l <= 0xFFFF);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen md_add_uint16(md, (uint16_t) l);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen gcry_md_write(md, (uint8_t*) rr->wire_format + rr->wire_format_rdata_offset, l);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen }
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen hash = gcry_md_read(md, 0);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (!hash) {
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen r = -EIO;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen goto finish;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen }
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (*(uint8_t*) dnskey->dnskey.key == 0) {
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen /* exponent is > 255 bytes long */
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen exponent = (uint8_t*) dnskey->dnskey.key + 3;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen exponent_size =
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen ((size_t) (((uint8_t*) dnskey->dnskey.key)[0]) << 8) |
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen ((size_t) ((uint8_t*) dnskey->dnskey.key)[1]);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (exponent_size < 256) {
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen r = -EINVAL;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen goto finish;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen }
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (3 + exponent_size >= dnskey->dnskey.key_size) {
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen r = -EINVAL;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen goto finish;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen }
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen } else {
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen /* exponent is <= 255 bytes long */
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen exponent = (uint8_t*) dnskey->dnskey.key + 1;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (exponent_size <= 0) {
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen r = -EINVAL;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen goto finish;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen }
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (1 + exponent_size >= dnskey->dnskey.key_size) {
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen r = -EINVAL;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen goto finish;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen }
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen }
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen r = dnssec_rsa_verify(
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen gcry_md_algo_name(gcry_md_get_algo(md)),
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen rrsig->rrsig.signature, rrsig->rrsig.signature_size,
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen hash, hash_size,
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen exponent, exponent_size,
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen modulus, modulus_size);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (r < 0)
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen goto finish;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = r ? DNSSEC_VERIFIED : DNSSEC_INVALID;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sieversfinish:
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers gcry_md_close(md);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return r;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers}
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sieversint dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers assert(rrsig);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers assert(dnskey);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* Checks if the specified DNSKEY RR matches the key used for
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers * the signature in the specified RRSIG RR */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (rrsig->key->type != DNS_TYPE_RRSIG)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return -EINVAL;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (dnskey->key->type != DNS_TYPE_DNSKEY)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (dnskey->key->class != rrsig->key->class)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (dnskey->dnskey.protocol != 3)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (dnssec_keytag(dnskey) != rrsig->rrsig.key_tag)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(rrsig->key));
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers}
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sieversint dnssec_key_match_rrsig(DnsResourceKey *key, DnsResourceRecord *rrsig) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers assert(key);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers assert(rrsig);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (rrsig->key->type != DNS_TYPE_RRSIG)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (rrsig->key->class != key->class)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (rrsig->rrsig.type_covered != key->type)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return 0;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers}
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sieversint dnssec_verify_rrset_search(
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers DnsAnswer *a,
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers DnsResourceKey *key,
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers DnsAnswer *validated_dnskeys,
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers usec_t realtime) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers bool found_rrsig = false, found_dnskey = false;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers DnsResourceRecord *rrsig;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers int r;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers assert(key);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* Verifies all RRs from "a" that match the key "key", against DNSKEY RRs in "validated_dnskeys" */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (!a || a->n_rrs <= 0)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return -ENODATA;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* Iterate through each RRSIG RR. */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers DNS_ANSWER_FOREACH(rrsig, a) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers DnsResourceRecord *dnskey;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = dnssec_key_match_rrsig(key, rrsig);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (r < 0)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return r;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (r == 0)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers continue;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers found_rrsig = true;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers DNS_ANSWER_FOREACH(dnskey, validated_dnskeys) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = dnssec_rrsig_match_dnskey(rrsig, dnskey);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (r < 0)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return r;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (r == 0)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers continue;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen found_dnskey = true;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen /* Take the time here, if it isn't set yet, so
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers * that we do all validations with the same
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers * time. */
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (realtime == USEC_INFINITY)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers realtime = now(CLOCK_REALTIME);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering /* Yay, we found a matching RRSIG with a matching
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek * DNSKEY, awesome. Now let's verify all entries of
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek * the RRSet against the RRSIG and DNSKEY
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering * combination. */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (r < 0 && r != EOPNOTSUPP)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering return r;
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek if (r == DNSSEC_VERIFIED)
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers return DNSSEC_VERIFIED;
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering /* If the signature is invalid, or done using
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering an unsupported algorithm, let's try another
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering key and/or signature. After all they
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering key_tags and stuff are not unique, and
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering might be shared by multiple keys. */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering }
b47d419c25ecc735615a1088060c1ec8bef1e41fZbigniew Jędrzejewski-Szmek }
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (found_dnskey)
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek return DNSSEC_INVALID;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (found_rrsig)
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek return DNSSEC_MISSING_KEY;
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek return DNSSEC_NO_SIGNATURE;
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek}
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmekint dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek size_t c = 0;
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek int r;
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering /* Converts the specified hostname into DNSSEC canonicalized
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering * form. */
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek
9c4495ca561624c2f0085507dd1288ed5f1247c5Tomasz Torcz if (buffer_max < 2)
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering return -ENOBUFS;
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering for (;;) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering size_t i;
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek r = dns_label_unescape(&n, buffer, buffer_max);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (r < 0)
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering return r;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (r == 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering break;
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering if (r > 0) {
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek int k;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering /* DNSSEC validation is always done on the ASCII version of the label */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering k = dns_label_apply_idna(buffer, r, buffer, buffer_max);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (k < 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return k;
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering if (k > 0)
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek r = k;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering }
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (buffer_max < (size_t) r + 2)
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek return -ENOBUFS;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering /* The DNSSEC canonical form is not clear on what to
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering * do with dots appearing in labels, the way DNS-SD
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering * does it. Refuse it for now. */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (memchr(buffer, '.', r))
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return -EINVAL;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering for (i = 0; i < (size_t) r; i ++) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (buffer[i] >= 'A' && buffer[i] <= 'Z')
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering buffer[i] = buffer[i] - 'A' + 'a';
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek }
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering buffer[r] = '.';
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering buffer += r + 1;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering c += r + 1;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering buffer_max -= r + 1;
458a2f85e8ae08c534bf8d030fbeeb791893422bTom Gundersen }
458a2f85e8ae08c534bf8d030fbeeb791893422bTom Gundersen
458a2f85e8ae08c534bf8d030fbeeb791893422bTom Gundersen if (c <= 0) {
458a2f85e8ae08c534bf8d030fbeeb791893422bTom Gundersen /* Not even a single label: this is the root domain name */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
458a2f85e8ae08c534bf8d030fbeeb791893422bTom Gundersen assert(buffer_max > 2);
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek buffer[0] = '.';
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering buffer[1] = 0;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return 1;
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek }
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek return (int) c;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering}
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poetteringint dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek gcry_md_hd_t md = NULL;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering void *result;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering int r;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering assert(dnskey);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering assert(ds);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek if (dnskey->key->type != DNS_TYPE_DNSKEY)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return -EINVAL;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (ds->key->type != DNS_TYPE_DS)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return -EINVAL;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return -EKEYREJECTED;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (dnskey->dnskey.protocol != 3)
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return -EKEYREJECTED;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek if (!dnssec_algorithm_supported(dnskey->dnskey.algorithm))
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return -EOPNOTSUPP;
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (!dnssec_digest_supported(ds->ds.digest_type))
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek return -EOPNOTSUPP;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (dnskey->dnskey.algorithm != ds->ds.algorithm)
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return 0;
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt if (dnssec_keytag(dnskey) != ds->ds.key_tag)
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek return 0;
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering switch (ds->ds.digest_type) {
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering case DNSSEC_DIGEST_SHA1:
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (ds->ds.digest_size != 20)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return 0;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering gcry_md_open(&md, GCRY_MD_SHA1, 0);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering break;
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek case DNSSEC_DIGEST_SHA256:
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (ds->ds.digest_size != 32)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return 0;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek gcry_md_open(&md, GCRY_MD_SHA256, 0);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering break;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek default:
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering assert_not_reached("Unknown digest");
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering }
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (!md)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return -EIO;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering if (r < 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering goto finish;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering gcry_md_write(md, owner_name, r);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering md_add_uint16(md, dnskey->dnskey.flags);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering md_add_uint8(md, dnskey->dnskey.protocol);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering md_add_uint8(md, dnskey->dnskey.algorithm);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering result = gcry_md_read(md, 0);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (!result) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = -EIO;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering goto finish;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering }
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering r = memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0;
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering
0238d4c660e732dd03ba0cdb54a29ec5870ee849Kay Sieversfinish:
0238d4c660e732dd03ba0cdb54a29ec5870ee849Kay Sievers gcry_md_close(md);
0238d4c660e732dd03ba0cdb54a29ec5870ee849Kay Sievers return r;
0238d4c660e732dd03ba0cdb54a29ec5870ee849Kay Sievers}
0238d4c660e732dd03ba0cdb54a29ec5870ee849Kay Sievers
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poetteringstatic const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = {
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering [DNSSEC_NO] = "no",
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek [DNSSEC_TRUST] = "trust",
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering [DNSSEC_YES] = "yes",
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering};
cca1dfddd4ce4357113663532696488427cc54e4Lennart PoetteringDEFINE_STRING_TABLE_LOOKUP(dnssec_mode, DnssecMode);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering