Commit e9aeeebe authored by Marek Vavruša's avatar Marek Vavruša

daemon/trust_anchors: finished state table, own module, cleanup

todo: active refresh
parent ad133f20
......@@ -16,8 +16,8 @@ daemon/engine.o: daemon/lua/sandbox.inc daemon/lua/config.inc
%.inc: %.lua
@$(call quiet,XXD,$<) $< > $@
# Installed FFI bindings
bindings-install: daemon/lua/kres.lua
$(INSTALL) $< $(PREFIX)/$(MODULEDIR)
bindings-install: daemon/lua/kres.lua daemon/lua/trust_anchors.lua
$(INSTALL) $^ $(PREFIX)/$(MODULEDIR)
# Dependencies
kresd_DEPEND := $(libkres)
......
......@@ -274,7 +274,6 @@ ffi.metatype( kr_request_t, {
})
-- Module API
local kres_context = ffi.cast('struct kr_context *', __engine)
local kres = {
-- Constants
class = ffi.new('struct rr_class'),
......@@ -288,131 +287,7 @@ local kres = {
-- Global API functions
str2dname = function(name) return ffi.string(ffi.gc(C.knot_dname_from_str(nil, name, 0), C.free)) end,
dname2str = function(dname) return ffi.string(ffi.gc(C.knot_dname_to_str(nil, dname, 0), C.free)) end,
context = function () return kres_context end,
}
-- RFC5011 state table
local key_state = {
Start = 'Start', AddPend = 'AddPend', Valid = 'Valid',
Missing = 'Missing', Revoked = 'Revoked', Removed = 'Removed'
}
-- Find key in current keyset
local function ta_find(keyset, rr)
for i = 1, #keyset do
local ta = keyset[i]
-- Match key owner and content
if ta.owner == rr.owner and
C.kr_dnssec_key_match(ta.rdata, #ta.rdata, rr.rdata, #rr.rdata) then
return ta
end
end
return nil
end
-- Evaluate TA status according to RFC5011
local function ta_present(keyset, rr, force)
if not C.kr_dnssec_key_ksk(rr.rdata) then
return false -- Ignore
end
-- Find the key in current key set and check its status
local key_revoked = C.kr_dnssec_key_revoked(rr.rdata)
local key_tag = C.kr_dnssec_key_tag(rr.type, rr.rdata, #rr.rdata)
local ta = ta_find(keyset, rr)
if ta then
-- Key reappears (KeyPres)
if ta.state == key_state.Missing then ta.state = key_state.Valid end
-- Key is revoked (RevBit)
if ta.state == key_state.Valid or ta.state == key_state.Missing then
if key_revoked then
ta.state = key_state.Revoked
-- @todo: ta.time = ...
end
end
-- @todo RemTime
-- @todo AddTime
-- Preserve key (KeyPres)
print('[trust_anchors] key: '..key_tag..' state: '..ta.state)
return true
elseif not key_revoked then -- First time seen (NewKey)
rr.state = force and key_state.Valid or key_state.AddPend
-- rr.time = ...
print('[trust_anchors] key: '..key_tag..' state: '..rr.state)
table.insert(keyset, rr)
return true
end
return false
end
-- TA is missing in the new key set
local function ta_missing(keyset, ta)
-- Key is removed (KeyRem)
if ta.state == key_state.Valid then
ta.state = key_state.Missing
-- ta.time = ...
elseif ta.state == key_state.AddPend then
-- @todo: remove from the set (Start)
end
local key_tag = C.kr_dnssec_key_tag(ta.type, ta.rdata, #ta.rdata)
print('[trust_anchors] key: '..key_tag..' state: '..ta.state)
end
-- TA store management
kres.trust_anchors = {
keyset = {},
insecure = {},
-- Update existing keyset
update = function (new_keys, initial)
-- Flag keys missing in new set (KeyRem)
local keyset = kres.trust_anchors.keyset
for i = 1, #keyset do
local ta = keyset[i]
if not ta_find(new_keys, ta) then
ta_missing(keyset, ta)
end
end
-- Evaluate new TAs
if not new_keys then return false end
for i = 1, #new_keys do
local rr = new_keys[i]
if rr.type == kres.type.DNSKEY then
ta_present(keyset, rr, initial)
end
end
-- Publish active TAs
local store = kres_context.trust_anchors
C.kr_ta_clear(store)
for i = 1, #keyset do
local ta = keyset[i]
-- Key MAY be used as a TA only in these two states (RFC5011, 4.2)
if ta.state == key_state.Valid or ta.state == key_state.Missing then
C.kr_ta_add(store, ta.owner, ta.type, ta.ttl, ta.rdata, #ta.rdata)
end
end
return true
end,
-- Load keys from a file (managed)
config = function (path)
local new_keys = require('zonefile').parse_file(path)
return kres.trust_anchors.update(new_keys, true)
end,
-- Add DS/DNSKEY record(s) (unmanaged)
add = function (keystr)
local store = kres_context.trust_anchors
require('zonefile').parser(function (p)
local rr = p:current_rr()
C.kr_ta_add(store, rr.owner, rr.type, rr.ttl, rr.rdata, #rr.rdata)
end):read(keystr..'\n')
end,
-- Negative TA management
set_insecure = function (list)
C.kr_ta_clear(kres_context.negative_anchors)
for i = 1, #list do
local dname = kres.str2dname(list[i])
C.kr_ta_add(kres_context.negative_anchors, dname, kres.type.DS, 0, nil, 0)
end
kres.trust_anchors.insecure = list
end,
context = function () return ffi.cast('struct kr_context *', __engine) end,
}
return kres
\ No newline at end of file
......@@ -6,9 +6,11 @@ GB = 1024*MB
sec = 1000
minute = 60 * sec
hour = 60 * minute
day = 24 * hour
-- Resolver bindings
kres = require('kres')
trust_anchors = require('trust_anchors')
-- Function aliases
-- `env.VAR returns os.getenv(VAR)`
......@@ -70,7 +72,6 @@ setmetatable(cache, {
cache.size = 10 * MB
-- Syntactic sugar for TA store
trust_anchors = kres.trust_anchors
setmetatable(trust_anchors, {
__newindex = function (t,k,v)
if k == 'file' then t.config(v)
......
local kres = require('kres')
local C = require('ffi').C
-- Add or remove hold-down timer
local hold_down_time = 30 * day
-- RFC5011 state table
local key_state = {
Start = 'Start', AddPend = 'AddPend', Valid = 'Valid',
Missing = 'Missing', Revoked = 'Revoked', Removed = 'Removed'
}
-- Find key in current keyset
local function ta_find(keyset, rr)
for i = 1, #keyset do
local ta = keyset[i]
-- Match key owner and content
if ta.owner == rr.owner and
C.kr_dnssec_key_match(ta.rdata, #ta.rdata, rr.rdata, #rr.rdata) then
return ta
end
end
return nil
end
-- Evaluate TA status according to RFC5011
local function ta_present(keyset, rr, force)
if not C.kr_dnssec_key_ksk(rr.rdata) then
return false -- Ignore
end
-- Find the key in current key set and check its status
local now = os.time()
local key_revoked = C.kr_dnssec_key_revoked(rr.rdata)
local key_tag = C.kr_dnssec_key_tag(rr.type, rr.rdata, #rr.rdata)
local ta = ta_find(keyset, rr)
if ta then
-- Key reappears (KeyPres)
if ta.state == key_state.Missing then
ta.state = key_state.Valid
ta.timer = nil
end
-- Key is revoked (RevBit)
if ta.state == key_state.Valid or ta.state == key_state.Missing then
if key_revoked then
ta.state = key_state.Revoked
ta.timer = os.time() + hold_down_time
end
end
-- Remove hold-down timer expires (RemTime)
if ta.state == key_state.Revoked and os.difftime(ta.timer, now) <= 0 then
ta.state = key_state.Removed
ta.timer = nil
end
-- Add hold-down timer expires (AddTime)
if ta.state == key_state.AddPend and os.difftime(ta.timer, now) <= 0 then
ta.state = key_state.Valid
ta.timer = nil
end
print('[trust_anchors] key: '..key_tag..' state: '..ta.state)
return true
elseif not key_revoked then -- First time seen (NewKey)
if force then
rr.state = key_state.Valid
else
rr.state = key_state.AddPend
rr.timer = now + hold_down_time
end
print('[trust_anchors] key: '..key_tag..' state: '..rr.state)
table.insert(keyset, rr)
return true
end
return false
end
-- TA is missing in the new key set
local function ta_missing(keyset, ta)
-- Key is removed (KeyRem)
local keep_ta = true
local key_tag = C.kr_dnssec_key_tag(ta.type, ta.rdata, #ta.rdata)
if ta.state == key_state.Valid then
ta.state = key_state.Missing
ta.timer = os.time() + hold_down_time
-- Purge pending key
elseif ta.state == key_state.AddPend then
print('[trust_anchors] key: '..key_tag..' purging')
keep_ta = false
end
print('[trust_anchors] key: '..key_tag..' state: '..ta.state)
return keep_ta
end
-- TA store management
local trust_anchors = {
keyset = {},
insecure = {},
-- Update existing keyset
update = function (new_keys, initial)
if not new_keys then return false end
-- Filter TAs to be purged from the keyset (KeyRem)
local keyset_keep = {}
local keyset = trust_anchors.keyset
for i = 1, #keyset do
local ta = keyset[i]
local keep = true
if not ta_find(new_keys, ta) then
keep = ta_missing(keyset, ta)
end
if keep then
table.insert(keyset_keep, rr)
end
end
keyset = keyset_keep
-- Evaluate new TAs
for i = 1, #new_keys do
local rr = new_keys[i]
if rr.type == kres.type.DNSKEY then
ta_present(keyset, rr, initial)
end
end
-- Publish active TAs
local store = kres.context().trust_anchors
C.kr_ta_clear(store)
for i = 1, #keyset do
local ta = keyset[i]
-- Key MAY be used as a TA only in these two states (RFC5011, 4.2)
if ta.state == key_state.Valid or ta.state == key_state.Missing then
C.kr_ta_add(store, ta.owner, ta.type, ta.ttl, ta.rdata, #ta.rdata)
end
end
trust_anchors.keyset = keyset
return true
end,
-- Load keys from a file (managed)
config = function (path)
local new_keys = require('zonefile').parse_file(path)
trust_anchors.update(new_keys, true)
end,
-- Add DS/DNSKEY record(s) (unmanaged)
add = function (keystr)
local store = kres.context().trust_anchors
require('zonefile').parser(function (p)
local rr = p:current_rr()
C.kr_ta_add(store, rr.owner, rr.type, rr.ttl, rr.rdata, #rr.rdata)
end):read(keystr..'\n')
end,
-- Negative TA management
set_insecure = function (list)
local store = kres.context().negative_anchors
C.kr_ta_clear(store)
for i = 1, #list do
local dname = kres.str2dname(list[i])
C.kr_ta_add(store, dname, kres.type.DS, 0, nil, 0)
end
trust_anchors.insecure = list
end,
}
return trust_anchors
\ No newline at end of file
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