Commit 3006b3b5 authored by Vladimír Čunát's avatar Vladimír Čunát

Merge !737: trust anchors improvements (mainly logs)

parents ec2de703 677282e5
......@@ -5,6 +5,14 @@ Bugfixes
--------
- policy.TLS_FORWARD: fix problems with gnutls 3.3 (#438)
Improvements
------------
- dnssec validation failures contain more verbose reasoning (!735)
- new function trust_anchors.summary() describes state of DNSSEC TAs (!737),
and logs new state of trust anchors after start up and automatic changes
- trust anchors: refuse revoked DNSKEY even if specified explicitly,
and downgrade missing the SEP bit to a warning
Knot Resolver 3.2.0 (2018-12-17)
================================
......
......@@ -728,6 +728,10 @@ Trust anchors and DNSSEC
> trust_anchors.add('. 3600 IN DS 19036 8 2 49AAC11...')
.. function:: trust_anchors.summary()
Return string with summary of configured DNSSEC trust anchors, including negative TAs.
Modules configuration
^^^^^^^^^^^^^^^^^^^^^
......
......@@ -416,6 +416,10 @@ local function keyset_publish(keyset)
end
end
end
if count == 0 then
warn('[ ta ] ERROR: no anchors are trusted for ' ..
kres.dname2str(keyset.owner) .. ' !')
end
return count
end
......@@ -470,10 +474,11 @@ update = function (keyset, new_keys, is_initial)
-- Start using the new TAs.
if keyset_publish(keyset) == 0 then
warn('[ ta ] WARNING: no anchors for ' .. kres.dname2str(keyset.owner)
.. ' are trusted!')
-- TODO: try to rebootstrap if for root?
return false
elseif verbose() then
log('[ ta ] refreshed trust anchors for domain ' .. kres.dname2str(keyset.owner) .. ' are:\n'
.. trust_anchors.summary(keyset.owner))
end
return true
......@@ -526,7 +531,9 @@ local add_file = function (path, unmanaged)
local owner = keyset[1].owner
for _, ta in ipairs(keyset) do
if ta.owner ~= owner then
panic("[ ta ] ERROR: mixed owner names found in '%s'", path)
panic("[ ta ] ERROR: mixed owner names found in file '%s'! " ..
"Do not mix %s and %s TAs in single file",
path, kres.dname2str(ta.owner), kres.dname2str(owner))
end
end
keyset.owner = owner
......@@ -540,13 +547,38 @@ local add_file = function (path, unmanaged)
trust_anchors.keysets[owner] = keyset
-- Parse new keys, refresh eventually
if keyset_publish(keyset) == 0 then
warn('[ ta ] ERROR: anchors are trusted for ' .. owner_str .. ' !')
-- TODO: try to rebootstrap?
if keyset_publish(keyset) ~= 0 and verbose() then
log('[ ta ] installed trust anchors for domain ' .. owner_str .. ' are:\n'
.. trust_anchors.summary(owner))
end
-- TODO: if failed and for root, try to rebootstrap?
refresh_plan(keyset, 10 * sec, false)
end
local function ta_str(owner)
local owner_str = kres.dname2str(owner) .. ' '
local msg = ''
for _, nta in pairs(trust_anchors.insecure) do
if owner == kres.str2dname(nta) then
msg = owner_str .. 'is negative trust anchor\n'
end
end
if not trust_anchors.keysets[owner] then
if #msg > 0 then -- it is normal that NTA does not have explicit TA
return msg
else
return owner_str .. 'has no explicit trust anchors\n'
end
end
if #msg > 0 then
msg = msg .. 'WARNING! negative trust anchor also has an explicit TA\n'
end
for _, ta in ipairs(trust_anchors.keysets[owner]) do
msg = msg .. kres.rr2str(ta) .. '\n'
end
return msg
end
-- TA store management, for user docs see ../README.rst
trust_anchors = {
......@@ -577,10 +609,13 @@ trust_anchors = {
-- Add DS/DNSKEY record(s) (unmanaged)
add = function (keystr)
return trustanchor(keystr)
local ret = trustanchor(keystr)
if verbose() then log(trust_anchors.summary()) end
return ret
end,
-- Negative TA management
set_insecure = function (list)
assert(type(list) == 'table', 'parameter must be list of domain names (e.g. {"a.test", "b.example"})')
local store = kres.context().negative_anchors
C.kr_ta_clear(store)
for i = 1, #list do
......@@ -589,6 +624,31 @@ trust_anchors = {
end
trust_anchors.insecure = list
end,
summary = function (single_owner)
if single_owner then -- single domain
return ta_str(single_owner)
end
-- all domains
local msg = ''
local ta_count = 0
local seen = {}
for _, nta_str in pairs(trust_anchors.insecure) do
local owner = kres.str2dname(nta_str)
seen[owner] = true
msg = msg .. ta_str(owner)
end
for owner, _ in pairs(trust_anchors.keysets) do
if not seen[owner] then
ta_count = ta_count + 1
msg = msg .. ta_str(owner)
end
end
if ta_count == 0 then
msg = msg .. 'No valid trust anchors, DNSSEC validation is disabled\n'
end
return msg
end,
}
-- Syntactic sugar for TA store
......
......@@ -23,6 +23,7 @@
#include <libdnssec/error.h>
#include "lib/defines.h"
#include "lib/dnssec.h"
#include "lib/dnssec/ta.h"
#include "lib/resolve.h"
#include "lib/utils.h"
......@@ -51,29 +52,34 @@ static int dnskey2ds(dnssec_binary_t *dst, const knot_dname_t *owner, const uint
{
dnssec_key_t *key = NULL;
int ret = dnssec_key_new(&key);
if (ret != DNSSEC_EOK) {
return kr_error(ENOMEM);
}
if (ret) goto cleanup;
/* Create DS from DNSKEY and reinsert */
const dnssec_binary_t key_data = { .size = rdlen, .data = (uint8_t *)rdata };
ret = dnssec_key_set_rdata(key, &key_data);
if (ret == DNSSEC_EOK) {
/* Accept only KSK (257) to TA store */
if (dnssec_key_get_flags(key) == 257) {
ret = dnssec_key_set_dname(key, owner);
} else {
ret = DNSSEC_EINVAL;
}
if (ret == DNSSEC_EOK) {
ret = dnssec_key_create_ds(key, DNSSEC_KEY_DIGEST_SHA256, dst);
}
if (ret) goto cleanup;
/* Accept only keys with Zone and SEP flags that aren't revoked,
* as a precaution. RFC 5011 also utilizes these flags.
* TODO: kr_dnssec_key_* names are confusing. */
const bool flags_ok = kr_dnssec_key_zsk(rdata) && !kr_dnssec_key_revoked(rdata);
if (!flags_ok) {
auto_free char *owner_str = kr_dname_text(owner);
kr_log_error("[ ta ] refusing to trust %s DNSKEY because of flags %d\n",
owner_str, dnssec_key_get_flags(key));
ret = kr_error(EILSEQ);
goto cleanup;
} else if (!kr_dnssec_key_ksk(rdata)) {
auto_free char *owner_str = kr_dname_text(owner);
int flags = dnssec_key_get_flags(key);
kr_log_info("[ ta ] warning: %s DNSKEY is missing the SEP bit; "
"flags %d instead of %d\n",
owner_str, flags, flags + 1/*a little ugly*/);
}
ret = dnssec_key_set_dname(key, owner);
if (ret) goto cleanup;
ret = dnssec_key_create_ds(key, DNSSEC_KEY_DIGEST_SHA256, dst);
cleanup:
dnssec_key_free(key);
/* Pick some sane error code */
if (ret != DNSSEC_EOK) {
return kr_error(ENOMEM);
}
return kr_ok();
return kr_error(ret);
}
/* @internal Insert new TA to trust anchor set, rdata MUST be of DS type. */
......@@ -91,10 +97,6 @@ static int insert_ta(map_t *trust_anchors, const knot_dname_t *name,
knot_rrset_free(ta_rr, NULL);
return kr_error(ENOMEM);
}
if(VERBOSE_STATUS) {
auto_free char *rr_text = kr_rrset_text(ta_rr);
kr_log_verbose("[ ta ] new state of trust anchors for a domain: %s\n", rr_text);
}
if (is_new_key) {
return map_set(trust_anchors, (const char *)name, ta_rr);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment