Commit 79419e77 authored by Jan Včelák's avatar Jan Včelák 🚀
Browse files

switch Knot to use libdnssec

+ private keys are not loaded at the moment
+ SIG(0) was temporarily removed
+ TSIG key files cannot be loaded
+ TSIG signing is disabled
parent f527a4f4
......@@ -186,19 +186,12 @@ src/libknot/consts.c
src/libknot/consts.h
src/libknot/dname.c
src/libknot/dname.h
src/libknot/dnssec/config.h
src/libknot/dnssec/crypto.c
src/libknot/dnssec/crypto.h
src/libknot/dnssec/key.c
src/libknot/dnssec/key.h
src/libknot/dnssec/policy.c
src/libknot/dnssec/policy.h
src/libknot/dnssec/rrset-sign.c
src/libknot/dnssec/rrset-sign.h
src/libknot/dnssec/sig0.c
src/libknot/dnssec/sig0.h
src/libknot/dnssec/sign.c
src/libknot/dnssec/sign.h
src/libknot/edns.c
src/libknot/edns.h
src/libknot/libknot.h
......@@ -213,7 +206,6 @@ src/libknot/rdata.c
src/libknot/rdata.h
src/libknot/rdata/dnskey.h
src/libknot/rdata/nsec.h
src/libknot/rdata/nsec3.c
src/libknot/rdata/nsec3.h
src/libknot/rdata/nsec3param.c
src/libknot/rdata/nsec3param.h
......@@ -284,10 +276,6 @@ tests/base64.c
tests/conf.c
tests/descriptor.c
tests/dname.c
tests/dnssec_keys.c
tests/dnssec_nsec3.c
tests/dnssec_sign.c
tests/dnssec_zone_nsec.c
tests/dthreads.c
tests/fdset.c
tests/hattrie.c
......
#include <ctype.h>
#include <stdio.h>
#include <yaml.h>
#include <dnssec/crypto.h>
#include <dnssec/error.h>
......@@ -53,9 +53,15 @@ int main(int argc, char *argv[])
printf("keytag ID\n");
for (size_t i = 0; i < keys_count; i++) {
const uint8_t *dname = dnssec_key_get_dname(keys[i].key);
const char *id = dnssec_key_get_id(keys[i].key);
uint16_t keytag = dnssec_key_get_keytag(keys[i].key);
printf("%-6d %s\n", keytag, id);
for (int i = 0; dname[i]; i++) {
if (isprint(dname[i])) { putchar(dname[i]); }
else { printf("%02x", dname[i]); }
}
printf("\n");
}
exit_code = 0;
......
ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
sbin_PROGRAMS = knotc knotd
bin_PROGRAMS = kdig khost knsupdate knsec3hash
bin_PROGRAMS = kdig khost knsupdate
lib_LTLIBRARIES = libknot.la
noinst_LTLIBRARIES = libknotd.la libknots.la libknotus.la
......@@ -56,9 +56,6 @@ knsupdate_SOURCES = \
utils/nsupdate/nsupdate_params.c \
utils/nsupdate/nsupdate_params.h
knsec3hash_SOURCES = \
utils/nsec3hash/nsec3hash_main.c
# static: shared
libknots_la_SOURCES = \
common/array-sort.h \
......@@ -141,9 +138,17 @@ libknot_la_SOURCES = \
libknot/consts.h \
libknot/dname.c \
libknot/dname.h \
libknot/dnssec/key.c \
libknot/dnssec/key.h \
libknot/dnssec/policy.c \
libknot/dnssec/policy.h \
libknot/dnssec/rrset-sign.c \
libknot/dnssec/rrset-sign.h \
libknot/edns.c \
libknot/edns.h \
libknot/libknot.h \
libknot/dnssec/key.c \
libknot/dnssec/key.h \
libknot/packet/compr.c \
libknot/packet/compr.h \
libknot/packet/pkt.c \
......@@ -154,7 +159,6 @@ libknot_la_SOURCES = \
libknot/rdata/rdname.h \
libknot/rdata/dnskey.h \
libknot/rdata/nsec.h \
libknot/rdata/nsec3.c \
libknot/rdata/nsec3.h \
libknot/rdata/nsec3param.h \
libknot/rdata/nsec3param.c \
......@@ -281,7 +285,7 @@ libknotd_la_SOURCES = \
knot/zone/zonedb.h
# libraries
libknot_la_LIBADD = libknots.la zscanner/libzscanner.la
libknot_la_LIBADD = libknots.la zscanner/libzscanner.la ../dnssec/libdnssec.la
libknotd_la_LIBADD = libknots.la libknot.la ../dnssec/libdnssec.la
libknotus_la_LIBADD = ../dnssec/libdnssec.la
......@@ -296,7 +300,6 @@ knotc_LDADD = libknot.la libknotd.la
kdig_LDADD = libknotus.la libknots.la libknot.la
khost_LDADD = libknotus.la libknots.la libknot.la
knsupdate_LDADD = libknotus.la libknots.la libknot.la zscanner/libzscanner.la
knsec3hash_LDADD = libknotus.la libknots.la libknot.la
# Create storage and run-time directories
install-data-hook:
......
......@@ -24,8 +24,7 @@
* @{
*/
#ifndef _KNOT_DNSSEC_NSEC_CHAIN_FIX_H_
#define _KNOT_DNSSEC_NSEC_CHAIN_FIX_H_
#pragma once
#include <stdbool.h>
#include <stdint.h>
......@@ -120,5 +119,3 @@ bool knot_nsec_empty_nsec_and_rrsigs_in_node(const knot_node_t *n);
*/
int knot_nsec_create_chain(const knot_zone_contents_t *zone, uint32_t ttl,
knot_changeset_t *changeset);
#endif // _KNOT_DNSSEC_NSEC_CHAIN_FIX_H_
......@@ -24,8 +24,7 @@
* @{
*/
#ifndef _KNOT_DNSSEC_NSEC3_CHAIN_FIX_H_
#define _KNOT_DNSSEC_NSEC3_CHAIN_FIX_H_
#pragma once
#include "knot/dnssec/zone-nsec.h"
#include "knot/dnssec/nsec-chain.h"
......@@ -41,5 +40,3 @@
*/
int knot_nsec3_create_chain(const knot_zone_contents_t *zone, uint32_t ttl,
knot_changeset_t *changeset);
#endif // _KNOT_DNSSEC_NSEC3_CHAIN_FIX_H_
......@@ -28,7 +28,7 @@
static int init_dnssec_structs(const knot_zone_contents_t *zone,
conf_zone_t *config,
knot_zone_keys_t *zone_keys,
zone_keyset_t *zone_keys,
knot_dnssec_policy_t *policy,
knot_update_serial_t soa_up, bool force)
{
......@@ -38,16 +38,13 @@ static int init_dnssec_structs(const knot_zone_contents_t *zone,
assert(config);
// Read zone keys from disk
bool nsec3_enabled = knot_is_nsec3_enabled(zone);
int result = knot_load_zone_keys(config->dnssec_keydir,
zone->apex->owner,
nsec3_enabled, zone_keys);
int result = load_zone_keys(config->dnssec_keydir, config->name, zone_keys);
if (result != KNOT_EOK) {
char *zname = knot_dname_to_str(zone->apex->owner);
log_zone_error("DNSSEC: Zone %s - %s\n", zname,
knot_strerror(result));
free(zname);
knot_free_zone_keys(zone_keys);
free_zone_keys(zone_keys);
return result;
}
......@@ -81,8 +78,8 @@ static int zone_sign(knot_zone_contents_t *zone, conf_zone_t *zone_config,
knot_changeset_is_empty(out_ch));
// Init needed structs
knot_zone_keys_t zone_keys = { '\0' };
knot_dnssec_policy_t policy = { '\0' };
zone_keyset_t zone_keys = { 0 };
knot_dnssec_policy_t policy = { 0 };
int result = init_dnssec_structs(zone, zone_config, &zone_keys, &policy,
soa_up, force);
if (result != KNOT_EOK) {
......@@ -97,7 +94,7 @@ static int zone_sign(knot_zone_contents_t *zone, conf_zone_t *zone_config,
log_zone_error("%s Could not create NSEC(3) chain (%s).\n",
msgpref, knot_strerror(result));
free(msgpref);
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
return result;
}
dbg_dnssec_verb("Changeset empty after generating NSEC chain: %d\n",
......@@ -110,7 +107,7 @@ static int zone_sign(knot_zone_contents_t *zone, conf_zone_t *zone_config,
log_zone_error("%s Error while signing (%s).\n",
msgpref, knot_strerror(result));
free(msgpref);
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
return result;
}
dbg_dnssec_verb("Changeset emtpy after signing: %d\n",
......@@ -122,7 +119,7 @@ static int zone_sign(knot_zone_contents_t *zone, conf_zone_t *zone_config,
log_zone_info("%s No signing performed, zone is valid.\n",
msgpref);
free(msgpref);
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
assert(knot_changeset_is_empty(out_ch));
return KNOT_EOK;
}
......@@ -137,11 +134,11 @@ static int zone_sign(knot_zone_contents_t *zone, conf_zone_t *zone_config,
log_zone_error("%s Cannot update SOA record (%s). Not signing"
"the zone!\n", msgpref, knot_strerror(result));
free(msgpref);
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
return result;
}
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
dbg_dnssec_detail("Zone signed: changes=%zu\n",
knot_changeset_size(out_ch));
free(msgpref);
......@@ -190,8 +187,8 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
}
// Init needed structures
knot_zone_keys_t zone_keys = { '\0' };
knot_dnssec_policy_t policy = { '\0' };
zone_keyset_t zone_keys = { 0 };
knot_dnssec_policy_t policy = { 0 };
int ret = init_dnssec_structs(zone, zone_config, &zone_keys, &policy,
soa_up, false);
if (ret != KNOT_EOK) {
......@@ -211,7 +208,7 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
if (ret != KNOT_EOK) {
log_zone_error("%s Failed to sign changeset (%s)\n", msgpref,
knot_strerror(ret));
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
free(msgpref);
return ret;
}
......@@ -221,7 +218,7 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
if (ret != KNOT_EOK) {
log_zone_error("%s Failed to create NSEC(3) chain (%s)\n",
msgpref, knot_strerror(ret));
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
free(msgpref);
return ret;
}
......@@ -232,7 +229,7 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
if (ret != KNOT_EOK) {
log_zone_error("%s Failed to sign changeset (%s)\n",
msgpref, knot_strerror(ret));
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
free(msgpref);
return ret;
}
......@@ -245,12 +242,12 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
if (ret != KNOT_EOK) {
log_zone_error("%s Failed to sign SOA RR (%s)\n", msgpref,
knot_strerror(ret));
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
free(msgpref);
return ret;
}
knot_free_zone_keys(&zone_keys);
free_zone_keys(&zone_keys);
free(msgpref);
*refresh_at = policy.refresh_before; // only new signatures are made
......
......@@ -25,8 +25,8 @@
* \addtogroup dnssec
* @{
*/
#ifndef _KNOT_DNSSEC_ZONE_EVENTS_H_
#define _KNOT_DNSSEC_ZONE_EVENTS_H_
#pragma once
#include "knot/zone/zone.h"
#include "knot/updates/changesets.h"
......@@ -85,5 +85,4 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
knot_update_serial_t soa_up,
uint32_t *refresh_at, uint32_t new_serial);
#endif // _KNOT_DNSSEC_ZONE_EVENTS_H_
/*! @} */
......@@ -18,120 +18,131 @@
#include <dirent.h>
#include <stdbool.h>
#include <inttypes.h>
#include <limits.h>
#include "common/debug.h"
#include "common/errcode.h"
#include "common/mempattern.h"
#include "dnssec/error.h"
#include "dnssec/kasp.h"
#include "dnssec/keystore.h"
#include "dnssec/sign.h"
#include "libknot/common.h"
#include "libknot/dname.h"
#include "libknot/consts.h"
#include "libknot/rdata/dnskey.h"
#include "libknot/dnssec/sign.h"
#include "knot/dnssec/zone-keys.h"
/*!
* \brief Free DNSSEC signing context for each key.
* \brief Get zone key by a keytag.
*/
static void free_sign_contexts(knot_zone_keys_t *keys)
zone_key_t *get_zone_key(const zone_keyset_t *keyset, uint16_t search)
{
assert(keys);
for (int i = 0; i < keys->count; i++) {
knot_dnssec_sign_free(keys->keys[i].context);
keys->keys[i].context = NULL;
if (!keyset) {
return NULL;
}
}
/*!
* \brief Initialize DNSSEC signing context for each key.
*/
static int init_sign_contexts(knot_zone_keys_t *keys)
{
assert(keys);
for (int i = 0; i < keys->count; i++) {
knot_zone_key_t *key = &keys->keys[i];
key->context = knot_dnssec_sign_init(&key->dnssec_key);
if (key->context == NULL) {
free_sign_contexts(keys);
return KNOT_ENOMEM;
for (size_t i = 0; i < keyset->count; i++) {
zone_key_t *key = &keyset->keys[i];
uint16_t keytag = dnssec_key_get_keytag(key->key);
if (keytag == search) {
return key;
}
}
return KNOT_EOK;
return NULL;
}
/*!
* \brief Get zone key by a keytag.
* \brief Get key feature flags from key parameters.
*/
const knot_zone_key_t *knot_get_zone_key(const knot_zone_keys_t *keys,
uint16_t keytag)
static int set_key(dnssec_kasp_key_t *kasp_key, zone_key_t *zone_key)
{
if (!keys) {
return NULL;
}
assert(kasp_key);
assert(zone_key);
time_t now = time(NULL);
dnssec_kasp_key_timing_t *timing = &kasp_key->timing;
const knot_zone_key_t *result = NULL;
// cryptographic context
for (int i = 0; i < keys->count; i++) {
const knot_zone_key_t *key = &keys->keys[i];
if (key->dnssec_key.keytag == keytag) {
result = key;
break;
}
dnssec_sign_ctx_t *ctx = NULL;
int r = dnssec_sign_new(&ctx, kasp_key->key);
if (r != DNSSEC_EOK) {
return KNOT_ERROR;
}
return result;
}
/*!
* \brief Get key feature flags from key parameters.
*/
static void set_zone_key_flags(const knot_key_params_t *params,
knot_zone_key_t *key)
{
assert(params);
assert(key);
zone_key->key = kasp_key->key;
zone_key->ctx = ctx;
uint32_t now = time(NULL);
// next event computation
uint32_t next_event = UINT32_MAX;
uint32_t timestamps[4] = {
params->time_publish,
params->time_activate,
params->time_inactive,
params->time_delete
time_t next = LONG_MAX;
time_t timestamps[4] = {
timing->active,
timing->publish,
timing->remove,
timing->retire,
};
for (int i = 0; i < 4; i++) {
uint32_t ts = timestamps[i];
if (ts != 0 && now <= ts && ts < next_event) {
next_event = ts;
time_t ts = timestamps[i];
if (ts != 0 && now <= ts && ts < next) {
next = ts;
}
}
key->next_event = next_event;
zone_key->next_event = next;
// build flags
key->is_ksk = params->flags & KNOT_RDATA_DNSKEY_FLAG_KSK;
uint16_t flags = dnssec_key_get_flags(kasp_key->key);
zone_key->is_ksk = flags & KNOT_RDATA_DNSKEY_FLAG_KSK;
zone_key->is_zsk = !zone_key->is_ksk; // in future, (is_ksk && is_zsk) is possible
key->is_active = params->time_activate <= now &&
(params->time_inactive == 0 || now <= params->time_inactive);
zone_key->is_active = timing->active <= now &&
(timing->retire == 0 || now <= timing->retire);
zone_key->is_public = timing->publish <= now &&
(timing->remove == 0 || now <= timing->remove);
key->is_public = params->time_publish <= now &&
(params->time_delete == 0 || now <= params->time_delete);
return KNOT_EOK;
}
/*!
* \brief Check if key should be already removed from the zone.
*/
static bool was_removed(const knot_key_params_t *params)
static int load_private_keys(const char *kasp_dir, zone_keyset_t *keyset)
{
assert(params);
assert(kasp_dir);
assert(keyset);
time_t now = time(NULL);
int result = KNOT_EOK;
char *keystore_dir = NULL;
dnssec_keystore_t *keystore = NULL;
int length = asprintf(&keystore_dir, "%s/keys", kasp_dir);
if (length < 0) {
result = KNOT_ENOMEM;
goto fail;
}
return params->time_delete != 0 && now > params->time_delete;
result = dnssec_keystore_create_pkcs8_dir(&keystore, keystore_dir);
if (result != DNSSEC_EOK) {
goto fail;
}
for (size_t i = 0; i < keyset->count; i++) {
if (!keyset->keys[i].is_active) {
continue;
}
#warning "Missing private key loading here."
}
result = KNOT_EOK;
fail:
dnssec_keystore_close(keystore);
free(keystore_dir);
return result;
}
/*!
......@@ -139,183 +150,93 @@ static bool was_removed(const knot_key_params_t *params)
*
* \todo Maybe use dynamic list instead of fixed size array.
*/
int knot_load_zone_keys(const char *keydir_name, const knot_dname_t *zone_name,
bool nsec3_enabled, knot_zone_keys_t *keys)
int load_zone_keys(const char *keydir_name, const char *zone_name,
zone_keyset_t *keyset_ptr)
{
if (!keydir_name || !zone_name || !keys) {
if (!keydir_name || !zone_name || !keyset_ptr) {
return KNOT_EINVAL;
}
DIR *keydir = opendir(keydir_name);
if (!keydir) {
return KNOT_DNSSEC_ENOKEYDIR;
}
zone_keyset_t keyset = {0};
char *zname = knot_dname_to_str(zone_name);
char *msgpref = sprintf_alloc("DNSSEC: Zone %s -", zname);
free(zname);
if (msgpref == NULL) {
closedir(keydir);
return KNOT_ENOMEM;
int r = dnssec_kasp_open_dir(keydir_name, &keyset.kasp);
if (r != DNSSEC_EOK) {
log_zone_error("Zone %s: failed to open KASP - %s.\n",
zone_name, dnssec_strerror(r));
return KNOT_ERROR;
}
struct dirent entry_buf = { 0 };
struct dirent *entry = NULL;
while (keys->count < KNOT_MAX_ZONE_KEYS &&
readdir_r(keydir, &entry_buf, &entry) == 0 &&
entry != NULL) {
char *suffix = strrchr(entry->d_name, '.');
if (!suffix) {
continue;
}
if (strcmp(suffix, ".private") != 0) {
continue;
}
size_t path_len = strlen(keydir_name) + 1 + strlen(entry->d_name);
char *path = malloc((path_len + 1) * sizeof(char));
if (!path) {
ERR_ALLOC_FAILED;
closedir(keydir);
free(msgpref);
return KNOT_ENOMEM;
}
int written = snprintf(path, path_len + 1, "%s/%s",
keydir_name, entry->d_name);
UNUSED(written);
assert(written == path_len);
dbg_dnssec_detail("loading key '%s'\n", path);
knot_key_params_t params = { 0 };
int result = knot_load_key_params(path, &params);
free(path);
if (result != KNOT_EOK) {
log_zone_warning("DNSSEC: Failed to load key %s: %s\n",
entry->d_name, knot_strerror(result));
knot_free_key_params(&params);
continue;
}
if (!knot_dname_is_equal(zone_name, params.name)) {
dbg_dnssec_detail("skipping key, different zone name\n");
knot_free_key_params(&params);
continue;
}
if (knot_get_key_type(&params) != KNOT_KEY_DNSSEC) {
dbg_dnssec_detail("skipping key, different purpose\n");
knot_free_key_params(&params);
continue;
}
knot_zone_key_t key;
memset(&key, '\0', sizeof(key));
set_zone_key_flags(&params, &key);
dbg_dnssec_detail("next key event %" PRIu32 "\n", key.next_event);
if (!key.is_active && !key.is_public && !was_removed(&params)) {
log_zone_notice("%s Ignoring key %d (%s): "
"%s, %s.\n", msgpref, params.keytag,
entry->d_name,
key.is_active ? "active" : "inactive",
key.is_public ? "public" : "not-public");
knot_free_key_params(&params);
continue;
}
if (!knot_dnssec_algorithm_is_zonesign(params.algorithm,
nsec3_enabled)
) {
log_zone_notice("%s Ignoring key %d (%s): unknown "
"algorithm or non-NSEC3 algorithm when"
" NSEC3 is requested.\n", msgpref,
params.keytag, entry->d_name);
knot_free_key_params(&params);
continue;
}
if (knot_get_zone_key(keys, params.keytag) != NULL) {
log_zone_notice("%s Ignoring key %d (%s): duplicate "
"keytag.\n", msgpref, params.keytag,
entry->d_name);
knot_free_key_params(&params);
continue;