Commit 6b27038e authored by Libor Peltan's avatar Libor Peltan

libdnssec: removed 'event' subsystem not needed anymore

parent c1a28b06
......@@ -77,28 +77,17 @@ src/dnssec/lib/dnssec/binary.h
src/dnssec/lib/dnssec/crypto.h
src/dnssec/lib/dnssec/dnssec.h
src/dnssec/lib/dnssec/error.h
src/dnssec/lib/dnssec/event.h
src/dnssec/lib/dnssec/kasp.h
src/dnssec/lib/dnssec/key.h
src/dnssec/lib/dnssec/keyid.h
src/dnssec/lib/dnssec/keystate.h
src/dnssec/lib/dnssec/keystore.h
src/dnssec/lib/dnssec/keytag.h
src/dnssec/lib/dnssec/keyusage.h
src/dnssec/lib/dnssec/list.h
src/dnssec/lib/dnssec/nsec.h
src/dnssec/lib/dnssec/random.h
src/dnssec/lib/dnssec/sign.h
src/dnssec/lib/dnssec/tsig.h
src/dnssec/lib/error.c
src/dnssec/lib/event/action.h
src/dnssec/lib/event/action/initial_key.c
src/dnssec/lib/event/action/nsec3_resalt.c
src/dnssec/lib/event/action/zsk_rollover.c
src/dnssec/lib/event/event.c
src/dnssec/lib/event/keystate.c
src/dnssec/lib/event/utils.c
src/dnssec/lib/event/utils.h
src/dnssec/lib/kasp/dir/dir.c
src/dnssec/lib/kasp/dir/escape.c
src/dnssec/lib/kasp/dir/escape.h
......@@ -138,7 +127,6 @@ src/dnssec/lib/keystore/keystore.c
src/dnssec/lib/keystore/pkcs11.c
src/dnssec/lib/keystore/pkcs8.c
src/dnssec/lib/keystore/pkcs8_dir.c
src/dnssec/lib/keyusage/keyusage.c
src/dnssec/lib/list/list.c
src/dnssec/lib/list/ucw_clists.h
src/dnssec/lib/nsec/bitmap.c
......@@ -174,8 +162,6 @@ src/dnssec/shared/timestamp.h
src/dnssec/shared/wire.h
src/dnssec/tests/binary.c
src/dnssec/tests/crypto.c
src/dnssec/tests/event_keystate.c
src/dnssec/tests/event_nsec3_resalt.c
src/dnssec/tests/kasp_dir_escape.c
src/dnssec/tests/kasp_dir_file.c
src/dnssec/tests/kasp_policy.c
......@@ -188,7 +174,6 @@ src/dnssec/tests/keystore_pkcs11.c
src/dnssec/tests/keystore_pkcs8.c
src/dnssec/tests/keystore_pkcs8_dir.c
src/dnssec/tests/keytag.c
src/dnssec/tests/keyusage.c
src/dnssec/tests/list.c
src/dnssec/tests/nsec_bitmap.c
src/dnssec/tests/nsec_hash.c
......
......@@ -457,17 +457,6 @@ of the limitations will be hopefully removed in the near future.
- Legacy key export is not implemented.
- DS record export is not implemented.
.. _dnssec-keyusage:
DNSSEC keys used by multiple zones
----------------------------------
Using same key for multiple zones with automatic key management is possible.
However, all zones must be listed in keyusage (keys directory) or they will be deleted,
when they retire in any zone.
If keys are added manually as published, but not active (for next rollover event), they are added automatically.
Performance Tuning
==================
......
......@@ -59,13 +59,10 @@ include_dnssec_HEADERS = \
lib/dnssec/crypto.h \
lib/dnssec/dnssec.h \
lib/dnssec/error.h \
lib/dnssec/event.h \
lib/dnssec/kasp.h \
lib/dnssec/key.h \
lib/dnssec/keyid.h \
lib/dnssec/keystate.h \
lib/dnssec/keystore.h \
lib/dnssec/keyusage.h \
lib/dnssec/keytag.h \
lib/dnssec/list.h \
lib/dnssec/nsec.h \
......@@ -78,14 +75,6 @@ libdnssec_la_SOURCES = \
lib/binary.c \
lib/crypto.c \
lib/error.c \
lib/event/action.h \
lib/event/action/initial_key.c \
lib/event/action/nsec3_resalt.c \
lib/event/action/zsk_rollover.c \
lib/event/event.c \
lib/event/keystate.c \
lib/event/utils.c \
lib/event/utils.h \
lib/kasp/dir/dir.c \
lib/kasp/dir/escape.c \
lib/kasp/dir/escape.h \
......@@ -125,7 +114,6 @@ libdnssec_la_SOURCES = \
lib/keystore/pkcs11.c \
lib/keystore/pkcs8.c \
lib/keystore/pkcs8_dir.c \
lib/keyusage/keyusage.c \
lib/list/list.c \
lib/list/ucw_clists.h \
lib/nsec/bitmap.c \
......
......@@ -105,14 +105,11 @@
#include <dnssec/binary.h>
#include <dnssec/crypto.h>
#include <dnssec/error.h>
#include <dnssec/event.h>
#include <dnssec/kasp.h>
#include <dnssec/key.h>
#include <dnssec/keyid.h>
#include <dnssec/keystate.h>
#include <dnssec/keystore.h>
#include <dnssec/keytag.h>
#include <dnssec/keyusage.h>
#include <dnssec/list.h>
#include <dnssec/nsec.h>
#include <dnssec/random.h>
......
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <time.h>
#include <dnssec/kasp.h>
#include <dnssec/keystore.h>
enum dnssec_event_type {
DNSSEC_EVENT_NONE = 0,
DNSSEC_EVENT_GENERATE_INITIAL_KEY,
DNSSEC_EVENT_ZSK_ROLL_PUBLISH_NEW_KEY,
DNSSEC_EVENT_ZSK_ROLL_REPLACE_SIGNATURES,
DNSSEC_EVENT_ZSK_ROLL_REMOVE_OLD_KEY,
DNSSEC_EVENT_NSEC3_RESALT,
};
typedef enum dnssec_event_type dnssec_event_type_t;
/*!
* Get user-readable name of DNSSEC event.
*/
const char *dnssec_event_name(dnssec_event_type_t event);
// TODO: disclose
struct dnssec_event {
time_t time;
dnssec_event_type_t type;
};
typedef struct dnssec_event dnssec_event_t;
struct dnssec_event_ctx {
time_t now;
dnssec_kasp_t *kasp;
dnssec_kasp_zone_t *zone;
dnssec_kasp_policy_t *policy;
dnssec_keystore_t *keystore;
};
typedef struct dnssec_event_ctx dnssec_event_ctx_t;
/*!
* Get next DNSSEC event to be executed.
*/
int dnssec_event_get_next(dnssec_event_ctx_t *ctx, dnssec_event_t *event);
/*!
* Execute given DNSSEC event.
*/
int dnssec_event_execute(dnssec_event_ctx_t *ctx, dnssec_event_t *event);
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <time.h>
#include "dnssec/kasp.h"
enum key_state {
DNSSEC_KEY_STATE_INVALID = 0,
DNSSEC_KEY_STATE_PUBLISHED,
DNSSEC_KEY_STATE_ACTIVE,
DNSSEC_KEY_STATE_RETIRED,
DNSSEC_KEY_STATE_REMOVED,
};
typedef enum key_state key_state_t;
key_state_t dnssec_get_key_state(const dnssec_kasp_key_t *key, time_t moment);
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <dnssec/list.h>
#include "kasp.h"
typedef struct record {
char *key_id;
dnssec_list_t *zones;
} record_keyusage_t;
typedef dnssec_list_t dnssec_keyusage_t;
char *dnssec_keyusage_path(dnssec_kasp_t *kasp);
int dnssec_keyusage_add(dnssec_keyusage_t *keyusage, const char *key_id, char *zone);
int dnssec_keyusage_remove(dnssec_keyusage_t *keyusage, const char *key_id, char *zone);
bool dnssec_keyusage_is_used(dnssec_keyusage_t *keyusage, const char *key_id);
int dnssec_keyusage_load(dnssec_keyusage_t *keyusage, const char *filename);
int dnssec_keyusage_save(dnssec_keyusage_t *keyusage, const char *filename);
dnssec_keyusage_t *dnssec_keyusage_new(void);
void dnssec_keyusage_free(dnssec_keyusage_t *keyusage);
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdbool.h>
#include "dnssec/event.h"
struct event_action_functions {
bool (*responds_to)(dnssec_event_type_t event);
int (*plan)(dnssec_event_ctx_t *ctx, dnssec_event_t *event);
int (*exec)(dnssec_event_ctx_t *ctx, const dnssec_event_t *event);
};
typedef struct event_action_functions event_action_functions_t;
extern const event_action_functions_t event_action_initial_key;
extern const event_action_functions_t event_action_zsk_rollover;
extern const event_action_functions_t event_action_nsec3_resalt;
/*!
* List of event implementations sorted by priority.
*/
static const event_action_functions_t * const EVENT_ACTION_HANDLERS[] = {
&event_action_initial_key,
&event_action_zsk_rollover,
&event_action_nsec3_resalt,
NULL,
};
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "dnssec/error.h"
#include "dnssec/event.h"
#include "key/internal.h"
#include "shared.h"
#include "event/action.h"
#include "event/utils.h"
#include "dnssec/keyusage.h"
/*!
* Scan zone keys and check if ZSK and KSK key exists.
*/
static void scan_keys(dnssec_kasp_zone_t *zone, bool *has_ksk, bool *has_zsk)
{
assert(zone);
assert(has_ksk);
assert(has_zsk);
*has_ksk = false;
*has_zsk = false;
dnssec_list_t *keys = dnssec_kasp_zone_get_keys(zone);
dnssec_list_foreach(i, keys) {
dnssec_kasp_key_t *key = dnssec_item_get(i);
uint16_t flags = dnssec_key_get_flags(key->key);
if (flags == DNSKEY_FLAGS_KSK) {
*has_ksk = true;
} else if (flags == DNSKEY_FLAGS_ZSK) {
*has_zsk = true;
}
}
}
/*!
* Generate key and start using it immediately.
*/
static int generate_initial_key(dnssec_event_ctx_t *ctx, bool ksk)
{
dnssec_kasp_key_t *key = NULL;
int r = generate_key(ctx, ksk, &key);
if (r != DNSSEC_EOK) {
return r;
}
if (!ksk) {
char *path = dnssec_keyusage_path(ctx->kasp);
if (path == NULL) {
return DNSSEC_ENOMEM;
}
dnssec_keyusage_t *keyusage = dnssec_keyusage_new();
dnssec_keyusage_load(keyusage, path);
dnssec_keyusage_add(keyusage, key->id, ctx->zone->name);
dnssec_keyusage_save(keyusage, path);
dnssec_keyusage_free(keyusage);
free(path);
}
key->timing.active = ctx->now;
key->timing.publish = ctx->now;
return DNSSEC_EOK;
}
static bool responds_to(dnssec_event_type_t type)
{
return type == DNSSEC_EVENT_GENERATE_INITIAL_KEY;
}
static int plan(dnssec_event_ctx_t *ctx, dnssec_event_t *event)
{
assert(ctx);
assert(event);
bool has_ksk, has_zsk;
scan_keys(ctx->zone, &has_ksk, &has_zsk);
if (!has_zsk || (!ctx->policy->singe_type_signing && !has_ksk)) {
event->type = DNSSEC_EVENT_GENERATE_INITIAL_KEY;
event->time = ctx->now;
} else {
clear_struct(event);
}
return DNSSEC_EOK;
}
static int exec(dnssec_event_ctx_t *ctx, const dnssec_event_t *event)
{
assert(ctx);
assert(event);
bool has_ksk, has_zsk;
scan_keys(ctx->zone, &has_ksk, &has_zsk);
if (has_ksk && has_zsk) {
return DNSSEC_EINVAL;
}
int r = DNSSEC_EOK;
if (!ctx->policy->singe_type_signing && !has_ksk) {
r = generate_initial_key(ctx, true);
}
if (r == DNSSEC_EOK && !has_zsk) {
r = generate_initial_key(ctx, false);
}
if (r == DNSSEC_EOK) {
r = dnssec_kasp_zone_save(ctx->kasp, ctx->zone);
}
return r;
}
const event_action_functions_t event_action_initial_key = {
.responds_to = responds_to,
.plan = plan,
.exec = exec
};
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "dnssec/binary.h"
#include "dnssec/error.h"
#include "dnssec/random.h"
#include "event/action.h"
#include "event/utils.h"
static bool responds_to(dnssec_event_type_t event)
{
return event == DNSSEC_EVENT_NSEC3_RESALT;
}
static bool params_match(const dnssec_binary_t *salt,
const dnssec_kasp_policy_t *policy)
{
return salt->size == policy->nsec3_salt_length;
}
static int plan(dnssec_event_ctx_t *ctx, dnssec_event_t *event)
{
assert(ctx);
assert(event);
if (!ctx->policy->nsec3_enabled || ctx->policy->nsec3_salt_length == 0) {
return DNSSEC_EOK;
}
time_t next = 0;
if (!params_match(&ctx->zone->nsec3_salt, ctx->policy)) {
next = ctx->now;
} else {
if (ctx->now < ctx->zone->nsec3_salt_created) {
return DNSSEC_EINVAL;
}
time_t age = ctx->now - ctx->zone->nsec3_salt_created;
if (age >= ctx->policy->nsec3_salt_lifetime) {
next = ctx->now;
} else {
next = ctx->now + (ctx->policy->nsec3_salt_lifetime - age);
}
}
event->type = DNSSEC_EVENT_NSEC3_RESALT;
event->time = next;
return DNSSEC_EOK;
}
static int generate_salt(dnssec_binary_t *salt, uint16_t length)
{
assert(salt);
dnssec_binary_t new_salt = { 0 };
if (length > 0) {
int r = dnssec_binary_alloc(&new_salt, length);
if (r != DNSSEC_EOK) {
return r;
}
r = dnssec_random_binary(&new_salt);
if (r != DNSSEC_EOK) {
dnssec_binary_free(&new_salt);
return r;
}
}
dnssec_binary_free(salt);
*salt = new_salt;
return DNSSEC_EOK;
}
static int exec(dnssec_event_ctx_t *ctx, const dnssec_event_t *event)
{
assert(ctx);
assert(event);
assert(event->type == DNSSEC_EVENT_NSEC3_RESALT);
int r = generate_salt(&ctx->zone->nsec3_salt, ctx->policy->nsec3_salt_length);
if (r != DNSSEC_EOK) {
return r;
}
ctx->zone->nsec3_salt_created = ctx->now;
return dnssec_kasp_zone_save(ctx->kasp, ctx->zone);
}
/*! Event API. */
const event_action_functions_t event_action_nsec3_resalt = {
.responds_to = responds_to,
.plan = plan,
.exec = exec,
};
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "dnssec/error.h"
#include "dnssec/event.h"
#include "dnssec/keyusage.h"
#include "event/action.h"
#include "dnssec/keystate.h"
#include "event/utils.h"
#include "key/internal.h"
#include "shared.h"
/*
* Three stage ZSK key pre-publish rollover:
*
* 1. The new key is introduced in the key set.
* 2. All signatures are replaced with new ones.
* 3. The old key is removed from the key set.
*
* RFC 6781 (Section 4.1.1.1)
*/
typedef bool (*key_match_cb)(const dnssec_kasp_key_t *key, void *data);
static bool newer_key(const dnssec_kasp_key_t *prev, const dnssec_kasp_key_t *cur)
{
return cur->timing.created == 0 ||
cur->timing.created >= prev->timing.created;
}
static bool zsk_match(const dnssec_kasp_key_t *key, time_t now, key_state_t state)
{
return dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_ZSK &&
dnssec_get_key_state(key, now) == state;
}
static dnssec_kasp_key_t *last_key(dnssec_event_ctx_t *ctx, key_state_t state)
{
assert(ctx);
assert(ctx->zone);
dnssec_kasp_key_t *match = NULL;
dnssec_list_t *keys = dnssec_kasp_zone_get_keys(ctx->zone);
dnssec_list_foreach(i, keys) {
dnssec_kasp_key_t *key = dnssec_item_get(i);
if ((match == NULL || newer_key(match, key)) &&
zsk_match(key, ctx->now, state)
) {
match = key;
}
}
return match;
}
static bool responds_to(dnssec_event_type_t event)
{
switch (event) {
case DNSSEC_EVENT_ZSK_ROLL_PUBLISH_NEW_KEY:
case DNSSEC_EVENT_ZSK_ROLL_REPLACE_SIGNATURES:
case DNSSEC_EVENT_ZSK_ROLL_REMOVE_OLD_KEY:
return true;
default:
return false;
}
}
#define subzero(a, b) ((a) > (b) ? (a) - (b) : 0)
static int plan(dnssec_event_ctx_t *ctx, dnssec_event_t *event)
{
assert(ctx);
assert(event);
// Not supported with Single-Type signing.
if (ctx->policy->singe_type_signing) {
event->type = DNSSEC_EVENT_NONE;
return DNSSEC_EOK;
}
/*
* We should not start another rollover, if there is a rollover
* in progress. Therefore we will check the keys in reverse order
* to make sure all stages are finished.
*/
dnssec_kasp_key_t *retired = last_key(ctx, DNSSEC_KEY_STATE_RETIRED);
if (retired) {
if (ctx->now < retired->timing.retire) {
return DNSSEC_EINVAL;
}
uint32_t retired_time = ctx->now - retired->timing.retire;
uint32_t retired_need = ctx->policy->propagation_delay +
ctx->policy->zone_maximal_ttl;
event->type = DNSSEC_EVENT_ZSK_ROLL_REMOVE_OLD_KEY;
event->time = ctx->now + subzero(retired_need, retired_time);
return DNSSEC_EOK;
}
dnssec_kasp_key_t *rolling = last_key(ctx, DNSSEC_KEY_STATE_PUBLISHED);
if (rolling) {
if (ctx->now < rolling->timing.publish) {
return DNSSEC_EINVAL;
}
uint32_t rolling_time = ctx->now - rolling->timing.publish;
uint32_t rolling_need = ctx->policy->propagation_delay +
ctx->policy->dnskey_ttl;
event->type = DNSSEC_EVENT_ZSK_ROLL_REPLACE_SIGNATURES;
event->time = ctx->now + subzero(rolling_need, rolling_time);
return DNSSEC_EOK;
}
dnssec_kasp_key_t *active = last_key(ctx, DNSSEC_KEY_STATE_ACTIVE);
if (active) {
if (ctx->now < active->timing.publish) {
return DNSSEC_EINVAL;
}
uint32_t active_age = ctx->now - active->timing.publish;
uint32_t active_max = ctx->policy->zsk_lifetime;
event->type = DNSSEC_EVENT_ZSK_ROLL_PUBLISH_NEW_KEY;
event->time = ctx->now + subzero(active_max, active_age);
return DNSSEC_EOK;
}
return DNSSEC_EINVAL;
}
static int exec_new_key(dnssec_event_ctx_t *ctx)
{
dnssec_kasp_key_t *new_key = NULL;
int r = generate_key(ctx, false, &new_key);
if (r != DNSSEC_EOK) {
return r;
}
//! \todo Cannot set "active" to zero, using upper bound instead.
new_key->timing.publish = ctx->now;
new_key->timing.active = UINT32_MAX;
return dnssec_kasp_zone_save(ctx->kasp, ctx->zone);
}
static int exec_new_signatures(dnssec_event_ctx_t *ctx)
{
dnssec_kasp_key_t *active = last_key(ctx, DNSSEC_KEY_STATE_ACTIVE);
dnssec_kasp_key_t *rolling = last_key(ctx, DNSSEC_KEY_STATE_PUBLISHED);
if (!active || !rolling) {
return DNSSEC_EINVAL;