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