resolved-dns-trust-anchor.c revision 105f6c4bdcdd9c7233370f1bc143913d5ab0d099
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2015 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sd-messages.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "alloc-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "conf-files.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "def.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "dns-domain.h"
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "fd-util.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fileio.h"
96aad8d15a324d0e956a4e5653a11a67b209b41aLennart Poettering#include "hexdecoct.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "parse-util.h"
23c80348e656a4e6fd9ba8f17523a65b6fa349a0Kay Sievers#include "resolved-dns-trust-anchor.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "resolved-dns-dnssec.h"
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering#include "set.h"
25300b5a1fcf54674a69d0f4ab08925be00b0227Lennart Poettering#include "string-util.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "strv.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering
003dffde2c1b93afbc9aff24b277276f65424406Lennart Poetteringstatic const char trust_anchor_dirs[] = CONF_PATHS_NULSTR("dnssec-trust-anchors.d");
4cee5eede280b7fd48c18a1942616c4ac896a554Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering/* The DS RR from https://data.iana.org/root-anchors/root-anchors.xml, retrieved December 2015 */
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poetteringstatic const uint8_t root_digest[] =
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering { 0x49, 0xAA, 0xC1, 0x1D, 0x7B, 0x6F, 0x64, 0x46, 0x70, 0x2E, 0x54, 0xA1, 0x60, 0x73, 0x71, 0x60,
15a5e95075a7f6007dd97b2a165c8ed16fe683dfLennart Poettering 0x7A, 0x1A, 0x41, 0x85, 0x52, 0x00, 0xFD, 0x2C, 0xE1, 0xCD, 0xDE, 0x32, 0xF2, 0x4E, 0x8F, 0xB5 };
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poetteringstatic int dns_trust_anchor_add_builtin(DnsTrustAnchor *d) {
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering int r;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering assert(d);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = hashmap_ensure_allocated(&d->positive_by_key, &dns_resource_key_hash_ops);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (r < 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return r;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DS, ".")))
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return 0;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DNSKEY, ".")))
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return 0;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering /* Add the RR from https://data.iana.org/root-anchors/root-anchors.xml */
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (!rr)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return -ENOMEM;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering rr->ds.key_tag = 19036;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering rr->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering rr->ds.digest_type = DNSSEC_DIGEST_SHA256;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering rr->ds.digest_size = sizeof(root_digest);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering rr->ds.digest = memdup(root_digest, rr->ds.digest_size);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (!rr->ds.digest)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return -ENOMEM;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering answer = dns_answer_new(1);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (!answer)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return -ENOMEM;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = dns_answer_add(answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (r < 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return r;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = hashmap_put(d->positive_by_key, rr->key, answer);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (r < 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return r;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
5bcd08db289cd02aad8a89b37b2a46244a7bd473Lennart Poettering answer = NULL;
cb81cd8073392936882643af0129934bf67e96c4Lennart Poettering return 0;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering}
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringstatic int dns_trust_anchor_load_positive(DnsTrustAnchor *d, const char *path, unsigned line, const char *s) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering _cleanup_free_ char *domain = NULL, *class = NULL, *type = NULL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering DnsAnswer *old_answer = NULL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering const char *p = s;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering int r;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering assert(d);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering assert(line);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = extract_first_word(&p, &domain, NULL, EXTRACT_QUOTES);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (r < 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_warning_errno(r, "Unable to parse domain in line %s:%u: %m", path, line);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (!dns_name_is_valid(domain)) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering log_warning("Domain name %s is invalid, at line %s:%u, ignoring line.", domain, path, line);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return -EINVAL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering }
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = extract_many_words(&p, NULL, 0, &class, &type, NULL);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (r < 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_warning_errno(r, "Unable to parse class and type in line %s:%u: %m", path, line);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (r != 2) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering log_warning("Missing class or type in line %s:%u", path, line);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return -EINVAL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering }
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (!strcaseeq(class, "IN")) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering log_warning("RR class %s is not supported, ignoring line %s:%u.", class, path, line);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return -EINVAL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering }
5bcd08db289cd02aad8a89b37b2a46244a7bd473Lennart Poettering
cb81cd8073392936882643af0129934bf67e96c4Lennart Poettering if (strcaseeq(type, "DS")) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering _cleanup_free_ char *key_tag = NULL, *algorithm = NULL, *digest_type = NULL, *digest = NULL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering _cleanup_free_ void *dd = NULL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering uint16_t kt;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering int a, dt;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering size_t l;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = extract_many_words(&p, NULL, 0, &key_tag, &algorithm, &digest_type, &digest, NULL);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (r < 0) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering log_warning_errno(r, "Failed to parse DS parameters on line %s:%u: %m", path, line);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return -EINVAL;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r != 4) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_warning("Missing DS parameters on line %s:%u", path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -EINVAL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = safe_atou16(key_tag, &kt);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return log_warning_errno(r, "Failed to parse DS key tag %s on line %s:%u: %m", key_tag, path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering a = dnssec_algorithm_from_string(algorithm);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (a < 0) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering log_warning("Failed to parse DS algorithm %s on line %s:%u", algorithm, path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -EINVAL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering dt = dnssec_digest_from_string(digest_type);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (dt < 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_warning("Failed to parse DS digest type %s on line %s:%u", digest_type, path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -EINVAL;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering r = unhexmem(digest, strlen(digest), &dd, &l);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_warning("Failed to parse DS digest %s on line %s:%u", digest, path, line);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return -EINVAL;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering }
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, domain);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering if (!rr)
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering return log_oom();
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering rr->ds.key_tag = kt;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering rr->ds.algorithm = a;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering rr->ds.digest_type = dt;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering rr->ds.digest_size = l;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering rr->ds.digest = dd;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering dd = NULL;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering } else if (strcaseeq(type, "DNSKEY")) {
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering _cleanup_free_ char *flags = NULL, *protocol = NULL, *algorithm = NULL, *key = NULL;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering _cleanup_free_ void *k = NULL;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering uint16_t f;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering size_t l;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering int a;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering r = extract_many_words(&p, NULL, 0, &flags, &protocol, &algorithm, &key, NULL);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering if (r < 0)
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering return log_warning_errno(r, "Failed to parse DNSKEY parameters on line %s:%u: %m", path, line);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering if (r != 4) {
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering log_warning("Missing DNSKEY parameters on line %s:%u", path, line);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return -EINVAL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!streq(protocol, "3")) {
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering log_warning("DNSKEY Protocol is not 3 on line %s:%u", path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -EINVAL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = safe_atou16(flags, &f);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering return log_warning_errno(r, "Failed to parse DNSKEY flags field %s on line %s:%u", flags, path, line);
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering if ((f & DNSKEY_FLAG_ZONE_KEY) == 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_warning("DNSKEY lacks zone key bit set on line %s:%u", path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -EINVAL;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if ((f & DNSKEY_FLAG_REVOKE)) {
06820eafdbc3dd89cb1f7563564c7d91426709caLennart Poettering log_warning("DNSKEY is already revoked on line %s:%u", path, line);
06820eafdbc3dd89cb1f7563564c7d91426709caLennart Poettering return -EINVAL;
06820eafdbc3dd89cb1f7563564c7d91426709caLennart Poettering }
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering a = dnssec_algorithm_from_string(algorithm);
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering if (a < 0) {
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering log_warning("Failed to parse DNSKEY algorithm %s on line %s:%u", algorithm, path, line);
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering return -EINVAL;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering }
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering r = unbase64mem(key, strlen(key), &k, &l);
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering if (r < 0)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return log_warning_errno(r, "Failed to parse DNSKEY key data %s on line %s:%u", key, path, line);
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, domain);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!rr)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return log_oom();
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering rr->dnskey.flags = f;
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek rr->dnskey.protocol = 3;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering rr->dnskey.algorithm = a;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering rr->dnskey.key_size = l;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering rr->dnskey.key = k;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering k = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering } else {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_warning("RR type %s is not supported, ignoring line %s:%u.", type, path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -EINVAL;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering }
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!isempty(p)) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_warning("Trailing garbage on line %s:%u, ignoring line.", path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -EINVAL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = hashmap_ensure_allocated(&d->positive_by_key, &dns_resource_key_hash_ops);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return r;
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering old_answer = hashmap_get(d->positive_by_key, rr->key);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering answer = dns_answer_ref(old_answer);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = dns_answer_add_extend(&answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return log_error_errno(r, "Failed to add trust anchor RR: %m");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = hashmap_replace(d->positive_by_key, rr->key, answer);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return log_error_errno(r, "Failed to add answer to trust anchor: %m");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering old_answer = dns_answer_unref(old_answer);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering answer = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int dns_trust_anchor_load_negative(DnsTrustAnchor *d, const char *path, unsigned line, const char *s) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering _cleanup_free_ char *domain = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering const char *p = s;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering int r;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(d);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering r = extract_first_word(&p, &domain, NULL, EXTRACT_QUOTES);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
9030ca462bd13cd6536299814e4a71d5c5e85be9Lennart Poettering return log_warning_errno(r, "Unable to parse line %s:%u: %m", path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!dns_name_is_valid(domain)) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering log_warning("Domain name %s is invalid, at line %s:%u, ignoring line.", domain, path, line);
8aec412ff697bc14995746953912ca6fdf2c9ba8Lennart Poettering return -EINVAL;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!isempty(p)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_warning("Trailing garbage at line %s:%u, ignoring line.", path, line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -EINVAL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = set_ensure_allocated(&d->negative_by_name, &dns_name_hash_ops);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return r;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = set_put(d->negative_by_name, domain);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return log_oom();
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r > 0)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering domain = NULL;
7f0d207d2c816e0a8cb2742b0a789911f7c99356Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int dns_trust_anchor_load_files(
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering DnsTrustAnchor *d,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *suffix,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int (*loader)(DnsTrustAnchor *d, const char *path, unsigned n, const char *line)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_strv_free_ char **files = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char **f;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(d);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(suffix);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering assert(loader);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering r = conf_files_list_nulstr(&files, suffix, NULL, trust_anchor_dirs);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (r < 0)
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return log_error_errno(r, "Failed to enumerate %s trust anchor files: %m", suffix);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering STRV_FOREACH(f, files) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering _cleanup_fclose_ FILE *g = NULL;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering char line[LINE_MAX];
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering unsigned n = 0;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering g = fopen(*f, "r");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (!g) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (errno == ENOENT)
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering continue;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering log_warning_errno(errno, "Failed to open %s: %m", *f);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering FOREACH_LINE(line, g, log_warning_errno(errno, "Failed to read %s, ignoring: %m", *f)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char *l;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering n++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering l = strstrip(line);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (isempty(l))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (*l == ';')
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering (void) loader(d, *f, n, l);
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering }
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering }
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering return 0;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poetteringstatic void dns_trust_anchor_dump(DnsTrustAnchor *d) {
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering DnsAnswer *a;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering Iterator i;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(d);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (hashmap_isempty(d->positive_by_key))
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering log_info("No positive trust anchors defined.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_info("Positive Trust Anchors:");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering HASHMAP_FOREACH(a, d->positive_by_key, i) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering DnsResourceRecord *rr;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering DNS_ANSWER_FOREACH(rr, a)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_info("%s", dns_resource_record_to_string(rr));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (set_isempty(d->negative_by_name))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_info("No negative trust anchors defined.");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering else {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char *n;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_info("Negative trust anchors:");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering SET_FOREACH(n, d->negative_by_name, i)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_info("%s%s", n, endswith(n, ".") ? "" : ".");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_trust_anchor_load(DnsTrustAnchor *d) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(d);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* If loading things from disk fails, we don't consider this fatal */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering (void) dns_trust_anchor_load_files(d, ".positive", dns_trust_anchor_load_positive);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering (void) dns_trust_anchor_load_files(d, ".negative", dns_trust_anchor_load_negative);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* However, if the built-in DS fails, then we have a problem. */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering r = dns_trust_anchor_add_builtin(d);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (r < 0)
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return log_error_errno(r, "Failed to add trust anchor built-in: %m");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering dns_trust_anchor_dump(d);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return 0;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering}
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poetteringvoid dns_trust_anchor_flush(DnsTrustAnchor *d) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering DnsAnswer *a;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(d);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering while ((a = hashmap_steal_first(d->positive_by_key)))
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering dns_answer_unref(a);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering d->positive_by_key = hashmap_free(d->positive_by_key);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering d->negative_by_name = set_free_free(d->negative_by_name);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering}
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringint dns_trust_anchor_lookup_positive(DnsTrustAnchor *d, const DnsResourceKey *key, DnsAnswer **ret) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering DnsAnswer *a;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(d);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(key);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(ret);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* We only serve DS and DNSKEY RRs. */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (!IN_SET(key->type, DNS_TYPE_DS, DNS_TYPE_DNSKEY))
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering a = hashmap_get(d->positive_by_key, key);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!a)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *ret = dns_answer_ref(a);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 1;
a3e7f417d72ba3251fd6b3a228a2721a4b725a03Zbigniew Jędrzejewski-Szmek}
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poetteringint dns_trust_anchor_lookup_negative(DnsTrustAnchor *d, const char *name) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(d);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering assert(name);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return set_contains(d->negative_by_name, name);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering}
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int dns_trust_anchor_remove_revoked(DnsTrustAnchor *d, DnsResourceRecord *rr) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering _cleanup_(dns_answer_unrefp) DnsAnswer *new_answer = NULL;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering DnsAnswer *old_answer;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering int r;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering old_answer = hashmap_get(d->positive_by_key, rr->key);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (!old_answer)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return 0;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering new_answer = dns_answer_ref(old_answer);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = dns_answer_remove_by_rr(&new_answer, rr);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (r <= 0)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return r;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* We found the key! Warn the user */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering log_struct(LOG_WARNING,
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED),
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering LOG_MESSAGE("DNSSEC Trust anchor %s has been revoked. Please update the trust anchor, or upgrade your operating system."), strna(dns_resource_record_to_string(rr)),
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering "TRUST_ANCHOR=%s", dns_resource_record_to_string(rr),
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering NULL);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (dns_answer_size(new_answer) <= 0) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert_se(hashmap_remove(d->positive_by_key, rr->key) == old_answer);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering dns_answer_unref(old_answer);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return 1;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = hashmap_replace(d->positive_by_key, new_answer->items[0].rr->key, new_answer);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (r < 0)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return r;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering new_answer = NULL;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering dns_answer_unref(old_answer);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return 1;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int dns_trust_anchor_check_revoked_one(DnsTrustAnchor *d, DnsResourceRecord *revoked_dnskey) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering DnsAnswer *a;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering int r;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering assert(d);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering assert(revoked_dnskey);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering assert(revoked_dnskey->key->type == DNS_TYPE_DNSKEY);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering assert(revoked_dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering a = hashmap_get(d->positive_by_key, revoked_dnskey->key);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (a) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering DnsResourceRecord *anchor;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* First, look for the precise DNSKEY in our trust anchor database */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering DNS_ANSWER_FOREACH(anchor, a) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (anchor->dnskey.protocol != revoked_dnskey->dnskey.protocol)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (anchor->dnskey.algorithm != revoked_dnskey->dnskey.algorithm)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (anchor->dnskey.key_size != revoked_dnskey->dnskey.key_size)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering continue;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (((anchor->dnskey.flags ^ revoked_dnskey->dnskey.flags) | DNSKEY_FLAG_REVOKE) != DNSKEY_FLAG_REVOKE)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering continue;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (memcmp(anchor->dnskey.key, revoked_dnskey->dnskey.key, anchor->dnskey.key_size) != 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering continue;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering dns_trust_anchor_remove_revoked(d, anchor);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering break;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering a = hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(revoked_dnskey->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(revoked_dnskey->key)));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (a) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering DnsResourceRecord *anchor;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* Second, look for DS RRs matching this DNSKEY in our trust anchor database */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering DNS_ANSWER_FOREACH(anchor, a) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering r = dnssec_verify_dnskey(revoked_dnskey, anchor, true);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return r;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r == 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering continue;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering dns_trust_anchor_remove_revoked(d, anchor);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering break;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return 0;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringstatic bool dns_trust_anchor_knows_domain(DnsTrustAnchor *d, const char *name) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(d);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Returns true if there's an entry for the specified domain
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * name in our trust anchor */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering hashmap_contains(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DNSKEY, name)) ||
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering hashmap_contains(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DS, name));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringint dns_trust_anchor_check_revoked(DnsTrustAnchor *d, DnsAnswer *rrs, const DnsResourceKey *key) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering DnsResourceRecord *dnskey;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering int r;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering assert(d);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering assert(key);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* Looks for self-signed DNSKEY RRs in "rrs" that have been revoked. */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (key->type != DNS_TYPE_DNSKEY)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return 0;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering DNS_ANSWER_FOREACH(dnskey, rrs) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering DnsResourceRecord *rrsig;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering DnssecResult result;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = dns_resource_key_equal(key, dnskey->key);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (r < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return r;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (r == 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering continue;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Is this DNSKEY revoked? */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if ((dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE) == 0)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering continue;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Could this be interesting to us at all? If not,
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * there's no point in looking for and verifying a
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * self-signed RRSIG. */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (!dns_trust_anchor_knows_domain(d, DNS_RESOURCE_KEY_NAME(dnskey->key)))
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering continue;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Look for a self-signed RRSIG */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering DNS_ANSWER_FOREACH(rrsig, rrs) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (rrsig->key->type != DNS_TYPE_RRSIG)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering continue;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = dnssec_rrsig_match_dnskey(rrsig, dnskey, true);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (r < 0)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return r;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (r == 0)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering continue;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = dnssec_verify_rrset(rrs, key, rrsig, dnskey, USEC_INFINITY, &result);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (r < 0)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return r;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (result != DNSSEC_VALIDATED)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering continue;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Bingo! Now, act! */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = dns_trust_anchor_check_revoked_one(d, dnskey);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (r < 0)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return r;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering }
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering }
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return 0;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering}
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering