Commit a7c72081 authored by Filip Široký's avatar Filip Široký
Browse files

dnssec: add keyusage + removing retired dnssec keys

parent 1c7c652d
......@@ -64,6 +64,7 @@ include_dnssec_HEADERS = \
lib/dnssec/key.h \
lib/dnssec/keyid.h \
lib/dnssec/keystore.h \
lib/dnssec/keyusage.h \
lib/dnssec/keytag.h \
lib/dnssec/list.h \
lib/dnssec/nsec.h \
......@@ -124,6 +125,7 @@ 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 \
......
/* 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>
typedef struct record {
char *keytag;
dnssec_list_t *zones;
} record_keyusage_t;
typedef dnssec_list_t dnssec_keyusage_t;
int dnssec_keyusage_add(dnssec_keyusage_t *keyusage, const char *keytag, char *zone);
int dnssec_keyusage_remove(dnssec_keyusage_t *keyusage, const char *keytag, char *zone);
bool dnssec_keyusage_is_used(dnssec_keyusage_t *keyusage, const char *keytag);
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);
......@@ -22,6 +22,7 @@
#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.
......@@ -58,6 +59,19 @@ static int generate_initial_key(dnssec_event_ctx_t *ctx, bool ksk)
return r;
}
if (!ksk) {
char *path;
if (asprintf(&path, "%s/keyusage", ctx->kasp->functions->base_path(ctx->kasp->ctx)) == -1){
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;
......
......@@ -18,6 +18,7 @@
#include "dnssec/error.h"
#include "dnssec/event.h"
#include "dnssec/keyusage.h"
#include "event/action.h"
#include "event/keystate.h"
#include "event/utils.h"
......@@ -169,6 +170,17 @@ static int exec_new_signatures(dnssec_event_ctx_t *ctx)
active->timing.retire = ctx->now;
rolling->timing.active = ctx->now;
char *path;
if (asprintf(&path, "%s/keyusage", ctx->kasp->functions->base_path(ctx->kasp->ctx)) == -1){
return DNSSEC_ENOMEM;
}
dnssec_keyusage_t *keyusage = dnssec_keyusage_new();
dnssec_keyusage_load(keyusage, path);
dnssec_keyusage_add(keyusage, rolling->id, ctx->zone->name);
dnssec_keyusage_save(keyusage, path);
dnssec_keyusage_free(keyusage);
free(path);
return dnssec_kasp_zone_save(ctx->kasp, ctx->zone);
}
......@@ -179,7 +191,33 @@ static int exec_remove_old_key(dnssec_event_ctx_t *ctx)
return DNSSEC_EINVAL;
}
char *path;
if (asprintf(&path, "%s/keyusage", ctx->kasp->functions->base_path(ctx->kasp->ctx)) == -1){
return DNSSEC_ENOMEM;
}
dnssec_keyusage_t *keyusage = dnssec_keyusage_new();
dnssec_keyusage_load(keyusage, path);
dnssec_keyusage_remove(keyusage, retired->id, ctx->zone->name);
dnssec_keyusage_save(keyusage, path);
retired->timing.remove = ctx->now;
dnssec_list_foreach(item, ctx->zone->keys) {
dnssec_kasp_key_t *key = dnssec_item_get(item);
if (key->id == retired->id) {
dnssec_list_remove(item);
}
}
if (dnssec_keyusage_is_used(keyusage, retired->id)) {
dnssec_keyusage_free(keyusage);
free(path);
return dnssec_kasp_zone_save(ctx->kasp, ctx->zone);
}
dnssec_keyusage_free(keyusage);
free(path);
dnssec_keystore_remove_key(ctx->keystore, retired->id);
return dnssec_kasp_zone_save(ctx->kasp, ctx->zone);
}
......
/* 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/>.
*/
#include "dnssec/keyusage.h"
#include "error.h"
#include "string.h"
#include "dnssec.h"
#include <assert.h>
#include "error.h"
#include "kasp/dir/json.h"
#include "kasp/internal.h"
#include "shared.h"
#include <string.h>
int dnssec_keyusage_add(dnssec_keyusage_t *keyusage, const char *keytag, char *zone) {
char *lzone = strdup(zone);
dnssec_list_foreach(item, keyusage) {
record_keyusage_t *record = dnssec_item_get(item);
if (strcmp(record->keytag, keytag) == 0) {
if(!dnssec_list_contains(record->zones, lzone)) {
dnssec_list_append(record->zones, lzone);
}
return DNSSEC_EOK;
}
}
record_keyusage_t *record = malloc(sizeof(*record));
record->keytag = strdup(keytag);
record->zones = dnssec_list_new();
dnssec_list_append(record->zones, lzone);
dnssec_list_append(keyusage, record);
return DNSSEC_EOK;
}
int dnssec_keyusage_remove(dnssec_keyusage_t *keyusage, const char *keytag, char *zone) {
dnssec_list_foreach(item, keyusage) {
record_keyusage_t *record = dnssec_item_get(item);
if (strcmp(record->keytag, keytag) == 0) {
dnssec_list_foreach(item2, record->zones) {
char *tmp = dnssec_item_get(item2);
if(strcmp(tmp,zone)==0) {
free(tmp);
dnssec_list_remove(item2);
if (dnssec_list_is_empty(record->zones)) {
free(record->keytag);
dnssec_list_free(record->zones);
free(record);
dnssec_list_remove(item);
}
return DNSSEC_EOK;
}
}
}
}
return DNSSEC_ENOENT;
}
bool dnssec_keyusage_is_used(dnssec_keyusage_t *keyusage, const char *keytag) {
if (dnssec_list_is_empty(keyusage)) {
return false;
}
dnssec_list_foreach(item, keyusage) {
record_keyusage_t *record = dnssec_item_get(item);
if(record == NULL || record->keytag == NULL) {
return false;
}
if (strcmp(record->keytag, keytag) == 0) {
return !dnssec_list_is_empty(record->zones);
}
}
return false;
}
static int import_keyusage(dnssec_keyusage_t *keyusage, const json_t *json)
{
json_t *jrecord = NULL;
int a, b;
if (!json_is_array(json)) {
if (json_is_null(json)) {
return DNSSEC_EOK;
} else {
return DNSSEC_CONFIG_MALFORMED;
}
}
json_array_foreach(json, a, jrecord) {
json_t *jkeytag = NULL;
jkeytag = json_object_get(jrecord, "keytag");
record_keyusage_t *record = malloc(sizeof(*record));
if (record == NULL) {
return DNSSEC_ENOMEM;
}
int r = decode_string(jkeytag, &record->keytag);
if (r != DNSSEC_EOK) {
return r;
}
json_t *jzones = NULL, *jzone = NULL;
jzones = json_object_get(jrecord, "zones");
record->zones = dnssec_list_new();
json_array_foreach(jzones, b, jzone) {
char *zone;
int r = decode_string(jzone, &zone);
if (r != DNSSEC_EOK) {
return r;
}
dnssec_list_append(record->zones, zone);
}
dnssec_list_append(keyusage, record);
}
return DNSSEC_EOK;
}
static int export_keyusage(dnssec_keyusage_t *keyusage, json_t **json)
{
assert(keyusage);
assert(json);
record_keyusage_t *record;
int r;
if (dnssec_list_is_empty(keyusage)) {
return DNSSEC_EOK;
}
json_t *jrecords = json_array();
if (!jrecords) {
return DNSSEC_ENOMEM;
}
json_t *jkeytag = NULL;
json_t *jzone = NULL;
json_t *jzones = NULL;
dnssec_list_foreach(item, keyusage) {
record = dnssec_item_get(item);
json_t *jzones = json_array();
if (!jzones) {
json_array_clear(jrecords);
return DNSSEC_ENOMEM;
}
r = encode_string(&record->keytag, &jkeytag);
if (r != DNSSEC_EOK) {
json_decref(jkeytag);
goto error;
}
dnssec_list_foreach(item, record->zones) {
const char *zone = dnssec_item_get(item);
r = encode_string(&zone, &jzone);
if (r != DNSSEC_EOK) {
json_decref(jzone);
goto error;
}
if (json_array_append_new(jzones, jzone)) {
r = DNSSEC_ENOMEM;
goto error;
}
}
json_t *jrecord = json_object();
if (!jrecord) {
r = DNSSEC_ENOMEM;
goto error;
}
if (json_object_set(jrecord, "keytag",jkeytag)) {
json_object_clear(jrecord);
r = DNSSEC_ENOMEM;
goto error;
}
json_decref(jkeytag);
if (json_object_set(jrecord, "zones",jzones)) {
json_object_clear(jrecord);
r = DNSSEC_ENOMEM;
goto error;
}
json_decref(jzones);
if (json_array_append_new(jrecords, jrecord)) {
json_object_clear(jrecord);
r = DNSSEC_ENOMEM;
goto error;
}
}
*json = jrecords;
return DNSSEC_EOK;
error:
json_array_clear(jzones);
json_array_clear(jrecords);
return r;
}
int dnssec_keyusage_load(dnssec_keyusage_t *keyusage, const char *filename)
{
assert(keyusage);
assert(filename);
dnssec_list_clear(keyusage);
_cleanup_fclose_ FILE *file = fopen(filename, "r");
if (!file) {
return DNSSEC_NOT_FOUND;
}
json_error_t error = { 0 };
_json_cleanup_ json_t *json = json_loadf(file, JSON_LOAD_OPTIONS, &error);
if (!json) {
if (error.position != 1) {
return DNSSEC_CONFIG_MALFORMED;
} else {
return DNSSEC_EOK;
}
}
return import_keyusage(keyusage, json);
}
int dnssec_keyusage_save(dnssec_keyusage_t *keyusage, const char *filename)
{
assert(keyusage);
assert(filename);
_json_cleanup_ json_t *json = NULL;
int r = export_keyusage(keyusage, &json);
if (r != DNSSEC_EOK) {
return r;
}
_cleanup_fclose_ FILE *file = fopen(filename, "w");
if (!file) {
return DNSSEC_NOT_FOUND;
}
if (json)
{
r = json_dumpf(json, file, JSON_DUMP_OPTIONS);
if (r != DNSSEC_EOK) {
return r;
}
}
fputc('\n', file);
return DNSSEC_EOK;
}
/* -- public API ----------------------------------------------------------- */
_public_
dnssec_keyusage_t *dnssec_keyusage_new()
{
dnssec_keyusage_t *keyusage = dnssec_list_new();
return keyusage;
}
_public_
void dnssec_keyusage_free(dnssec_keyusage_t *keyusage)
{
if (keyusage == NULL) {
return;
}
if (!dnssec_list_is_empty(keyusage)) {
dnssec_list_foreach(item, keyusage) {
record_keyusage_t *record = dnssec_item_get(item);
free(record->keytag);
dnssec_list_foreach(item2, record->zones) {
char *zone = dnssec_item_get(item2);
free(zone);
}
dnssec_list_free(record->zones);
free(record);
}
}
dnssec_list_free(keyusage);
keyusage = NULL;
}
......@@ -9,6 +9,7 @@
/event_nsec3_resalt
/kasp_dir_escape
/kasp_dir_file
/keyusage
/kasp_policy
/kasp_store
/key
......
......@@ -34,6 +34,7 @@ check_PROGRAMS = \
keystore_pkcs8 \
keystore_pkcs8_dir \
keytag \
keyusage \
list \
nsec_bitmap \
nsec_hash \
......
/* 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/>.
*/
#include <tap/basic.h>
#include <string.h>
#include <stdio.h>
#include "dnssec/keyusage.h"
#include "dnssec/error.h"
#include "dnssec.h"
static void test_keyusage_empty(void)
{
diag("%s", __func__);
dnssec_keyusage_t *k = dnssec_keyusage_new();
remove("/tmp/keyusage.json");
ok(dnssec_keyusage_load(k, "/tmp/keyusage.json")== DNSSEC_NOT_FOUND, "kayusage_load empty, no keyusage");
ok(dnssec_list_is_empty(k), "List of records is empty.");
ok(dnssec_keyusage_save(k, "/tmp/keyusage.json") == DNSSEC_EOK , "kayusage_save empty");
ok(dnssec_keyusage_load(k, "/tmp/keyusage.json")== DNSSEC_EOK , "kayusage_load empty");
ok(dnssec_list_is_empty(k), "List of records is empty.");
dnssec_keyusage_free(k);
}
static void test_keyusage_basic(void)
{
diag("%s", __func__);
dnssec_keyusage_t *k = NULL;
k = dnssec_keyusage_new();
ok(dnssec_list_is_empty(k), "List of records is empty.");
dnssec_keyusage_add(k, "prvni", "zona");
ok(!dnssec_list_is_empty(k), "List of records is not empty.");
// Check added key being used
ok(dnssec_keyusage_is_used(k, "prvni"), "Key is used.");
// Remove added key and check empty record
dnssec_keyusage_remove(k, "prvni", "zona");
ok(dnssec_list_is_empty(k), "List of records is empty.");
ok(!dnssec_keyusage_is_used(k, "prvni"), "Key is not used.");
// Check if key is used when one of zones is deleted
dnssec_keyusage_add(k, "prvni", "zona");
dnssec_keyusage_add(k, "prvni", "zona2");
dnssec_keyusage_remove(k, "prvni", "zona");
ok(dnssec_keyusage_is_used(k, "prvni"), "Key is used.");
// Check if key is unused after deleting both zones
dnssec_keyusage_remove(k, "prvni", "zona2");
ok(!dnssec_keyusage_is_used(k, "prvni"), "Key is not used.");
dnssec_keyusage_free(k);
}
static void test_keyusage_file(void)
{
dnssec_keyusage_t *k = NULL;
k = dnssec_keyusage_new();
dnssec_keyusage_add(k, "prvni", "zona");
dnssec_keyusage_add(k, "prvni", "zona2");
dnssec_keyusage_add(k, "druhy", "zona");
ok(dnssec_keyusage_save(k, "/tmp/keyusage.json") == DNSSEC_EOK , "kayusage_save");
dnssec_keyusage_free(k);
k = dnssec_keyusage_new();
ok(!dnssec_keyusage_is_used(k, "prvni"), "Key is not used - freed succesfully.");
ok(!dnssec_keyusage_is_used(k, "druhy"), "Key is not used - freed succesfully.");
ok(dnssec_keyusage_load(k, "/tmp/keyusage.json")== DNSSEC_EOK , "kayusage_load");
ok(dnssec_keyusage_is_used(k, "prvni"), "Key is used - loaded succesfully.");
ok(dnssec_keyusage_is_used(k, "druhy"), "Key is used - loaded succesfully.");
dnssec_keyusage_free(k);
}
int main(int argc, char *argv[])
{
plan_lazy();
test_keyusage_empty();
test_keyusage_basic();
test_keyusage_file();
return 0;
}
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