diff --git a/src/knot/dnssec/kasp/kasp_zone.c b/src/knot/dnssec/kasp/kasp_zone.c index 49a18afc5..c98eceb0f 100644 --- a/src/knot/dnssec/kasp/kasp_zone.c +++ b/src/knot/dnssec/kasp/kasp_zone.c @@ -51,7 +51,7 @@ static int dnskey_guess_flags(dnssec_key_t *key, uint16_t keytag) } static int params2dnskey(const knot_dname_t *dname, key_params_t *params, - dnssec_key_t **key_ptr) + dnssec_key_t **key_ptr) { assert(dname); assert(params); @@ -93,8 +93,8 @@ static int params2dnskey(const knot_dname_t *dname, key_params_t *params, return KNOT_EOK; } -static int params2kaspkey(const knot_dname_t *dname, key_params_t *params, - knot_kasp_key_t *key) +int params2kaspkey(const knot_dname_t *dname, key_params_t *params, + knot_kasp_key_t *key) { assert(dname != NULL); assert(params != NULL); diff --git a/src/knot/dnssec/kasp/kasp_zone.h b/src/knot/dnssec/kasp/kasp_zone.h index 1c65d2e04..4ddb6dc7a 100644 --- a/src/knot/dnssec/kasp/kasp_zone.h +++ b/src/knot/dnssec/kasp/kasp_zone.h @@ -19,6 +19,9 @@ typedef struct { knot_time_t nsec3_salt_created; } knot_kasp_zone_t; +int params2kaspkey(const knot_dname_t *dname, key_params_t *params, + knot_kasp_key_t *key); + int kasp_zone_load(knot_kasp_zone_t *zone, const knot_dname_t *zone_name, knot_lmdb_db_t *kdb, diff --git a/src/utils/keymgr/functions.c b/src/utils/keymgr/functions.c index e545d63f5..4fe03816b 100644 --- a/src/utils/keymgr/functions.c +++ b/src/utils/keymgr/functions.c @@ -23,6 +23,7 @@ #include "contrib/wire_ctx.h" #include "libknot/dnssec/keyid.h" #include "libknot/dnssec/shared/shared.h" +#include "knot/dnssec/kasp/kasp_zone.h" #include "knot/dnssec/kasp/policy.h" #include "knot/dnssec/key-events.h" #include "knot/dnssec/rrset-sign.h" @@ -944,11 +945,18 @@ static const timer_ctx_t timers[] = { { NULL } }; +static const timer_ctx_t trash_timers[] = { + { "discard", offsetof(knot_kasp_key_timing_t, remove) }, + { NULL } +}; + typedef struct { const char *ks_name; size_t ks_count; unsigned backend; bool missing; + bool trash; + bool all_zones; } key_info_t; #define KS_TYPE(info) (info->backend == KEYSTORE_BACKEND_PEM) ? "PEM" : "PKCS11" @@ -992,9 +1000,10 @@ static void print_key_brief(const knot_kasp_key_t *key, key_info_t *info, printf(" %s%s/%s%s", COL_YELW(c), KS_TYPE(info), info->ks_name, COL_RST(c)); } - static char buf[100]; + static knot_dname_txt_storage_t buf; knot_time_t now = knot_time(); - for (const timer_ctx_t *t = &timers[0]; t->name != NULL; t++) { + for (const timer_ctx_t *t = info->trash ? &trash_timers[0] : &timers[0]; + t->name != NULL; t++) { knot_time_t *val = (void *)(&key->timing) + t->offset; if (*val == 0) { continue; @@ -1012,27 +1021,42 @@ static void print_key_brief(const knot_kasp_key_t *key, key_info_t *info, (void)knot_time_print(params->format, *val, buf, sizeof(buf)); printf(" %s%s%s=%s%s%s", UNDR, t->name, COL_RST(c), BOLD, buf, COL_RST(c)); } + if (info->trash && info->all_zones) { + if (knot_dname_to_str(buf, dnssec_key_get_dname(key->key), + sizeof(buf)) != NULL) { + printf(" zone=%s", buf); + } + } printf("\n"); } static void print_key_full(const knot_kasp_key_t *key, key_info_t *info, - knot_time_print_t format) + keymgr_list_params_t *params) { - printf("%s ksk=%s zsk=%s tag=%05d algorithm=%-2d size=%-4u public-only=%s for-later=%s missing=%s", + printf("%s ksk=%s zsk=%s tag=%05d algorithm=%-2d size=%-4u" + " public-only=%s for-later=%s missing=%s trash=%s", key->id, (key->is_ksk ? "yes" : "no "), (key->is_zsk ? "yes" : "no "), dnssec_key_get_keytag(key->key), (int)dnssec_key_get_algorithm(key->key), dnssec_key_get_size(key->key), (key->is_pub_only ? "yes" : "no "), - (key->is_for_later ? "yes" : "no "), (info->missing ? "yes" : "no ")); + (key->is_for_later ? "yes" : "no "), (info->missing ? "yes" : "no "), + (info->trash ? "yes" : "no ")); if (info->ks_name != NULL) { printf(" keystore=%s/%s", KS_TYPE(info), info->ks_name); } - static char buf[100]; - for (const timer_ctx_t *t = &timers[0]; t->name != NULL; t++) { + static knot_dname_txt_storage_t buf; + for (const timer_ctx_t *t = info->trash ? &trash_timers[0] : &timers[0]; + t->name != NULL; t++) { knot_time_t *val = (void *)(&key->timing) + t->offset; - (void)knot_time_print(format, *val, buf, sizeof(buf)); + (void)knot_time_print(params->format, *val, buf, sizeof(buf)); printf(" %s=%s", t->name, buf); } + if (info->trash) { + if (knot_dname_to_str(buf, dnssec_key_get_dname(key->key), + sizeof(buf)) != NULL) { + printf(" zone=%s", buf); + } + } printf("\n"); } @@ -1098,7 +1122,7 @@ int keymgr_list_keys(kdnssec_ctx_t *ctx, keymgr_list_params_t *params) for (size_t i = 0; i < ctx->zone->num_keys; i++) { knot_kasp_key_t *key = &ctx->zone->keys[i]; key_info_t info = key_missing(ctx, key); - print_key_full(key, &info, params->format); + print_key_full(key, &info, params); } } else if (params->json) { jsonw_t *w = jsonw_new(stdout, " "); @@ -1140,6 +1164,77 @@ int keymgr_list_keys(kdnssec_ctx_t *ctx, keymgr_list_params_t *params) return KNOT_EOK; } +static int print_params_key(kdnssec_ctx_t *ctx, key_params_t *kparams, + keymgr_list_params_t *params, + void (*print_cb)(const knot_kasp_key_t *, key_info_t *, + keymgr_list_params_t *)) +{ + knot_kasp_key_t key; + int ret = params2kaspkey(kparams->dname, kparams, &key); + if (ret != KNOT_EOK) { + ERR2("failed to parse key metadata (%s)", knot_strerror(ret)); + goto exit; + } + key_info_t info = key_missing(ctx, &key); + info.trash = true; + info.all_zones = ctx->validation_mode; // Abused parameter validation_mode. + print_cb(&key, &info, params); + +exit: + free(key.id); + dnssec_key_free(key.key); + return ret; +} + +int keymgr_list_trash(kdnssec_ctx_t *ctx, const knot_dname_t *zone_name, + keymgr_list_params_t *params) +{ + list_t tlist; + init_list(&tlist); + int ret = kasp_db_list_keys(ctx->kasp_db, zone_name, &tlist, true); + if (ret != KNOT_EOK) { + ERR2("failed to initialize KASP (%s)", knot_strerror(ret)); + return ret; + } + + ptrnode_t *node; + if (params->extended) { + WALK_LIST(node, tlist) { + ret = print_params_key(ctx, node->d, params, print_key_full); + if (ret != KNOT_EOK) { + break; + } + } + } else if (params->json) { +// XXXXXXX + ERR2("JSON trash key listing not supported (yet)"); + } else { + size_t tlist_size = list_size(&tlist); + key_sort_item_t items[tlist_size]; + + size_t i = 0; + WALK_LIST(node, tlist) { + items[i].val = node->d; + items[i].key = ((key_params_t *)node->d)->timing.remove; + i++; + } + qsort(&items, tlist_size, sizeof(items[0]), key_sort); + for (i = 0; i < tlist_size; i++) { + ret = print_params_key(ctx, items[i].val, params, print_key_brief); + if (ret != KNOT_EOK) { + break; + } + } + } + + WALK_LIST(node, tlist) { + free_key_params(node->d); + } + ptrlist_deep_free(&tlist, NULL); + + return ret; +} + static int print_ds(const knot_dname_t *dname, const dnssec_binary_t *rdata) { wire_ctx_t ctx = wire_ctx_init(rdata->data, rdata->size); diff --git a/src/utils/keymgr/functions.h b/src/utils/keymgr/functions.h index 21a046f72..044453013 100644 --- a/src/utils/keymgr/functions.h +++ b/src/utils/keymgr/functions.h @@ -46,6 +46,8 @@ int keymgr_set_timing(knot_kasp_key_t *key, int argc, char *argv[]); int keymgr_list_keys(kdnssec_ctx_t *ctx, keymgr_list_params_t *params); +int keymgr_list_trash(kdnssec_ctx_t *ctx, const knot_dname_t *zone_name, keymgr_list_params_t *params); + int keymgr_generate_ds(const knot_dname_t *dname, const knot_kasp_key_t *key); int keymgr_generate_dnskey(const knot_dname_t *dname, const knot_kasp_key_t *key); diff --git a/src/utils/keymgr/main.c b/src/utils/keymgr/main.c index 69c3f740e..13232b5a9 100644 --- a/src/utils/keymgr/main.c +++ b/src/utils/keymgr/main.c @@ -137,11 +137,27 @@ static int key_command(int argc, char *argv[], int opt_ind, knot_lmdb_db_t *kasp knot_dname_to_lower(zone_name); kdnssec_ctx_t kctx = { 0 }; + int ret; - int ret = kdnssec_ctx_init(conf(), &kctx, zone_name, kaspdb, NULL); - if (ret != KNOT_EOK) { - ERR2("failed to initialize KASP (%s)", knot_strerror(ret)); - goto main_end; + if (same_command(argv[1], "trash-list", false) || + same_command(argv[1], "trash-delete", false)) { + kctx.kasp_db = kaspdb; + ret = init_all_keystores(conf(), &kctx.keystores); + if (ret != KNOT_EOK) { + ERR2("failed to initialize keystores (%s)", knot_strerror(ret)); + goto main_end; + } + + if (strncmp(id_str, "--", 3)) { + kctx.validation_mode = true; // Abused parameter validation_mode. + zone_name = NULL; + } + } else { + ret = kdnssec_ctx_init(conf(), &kctx, zone_name, kaspdb, NULL); + if (ret != KNOT_EOK) { + ERR2("failed to initialize KASP (%s)", knot_strerror(ret)); + goto main_end; + } } #define CHECK_MISSING_ARG(msg) \ @@ -211,6 +227,15 @@ static int key_command(int argc, char *argv[], int opt_ind, knot_lmdb_db_t *kasp } ret = keymgr_list_keys(&kctx, list_params); print_ok_on_succes = false; + } else if (same_command(argv[1], "trash-list", false)) { + list_params->format = TIME_PRINT_UNIX; + if (argc > 2 && same_command(argv[2], "human", false)) { + list_params->format = TIME_PRINT_HUMAN_MIXED; + } else if (argc > 2 && same_command(argv[2], "iso", false)) { + list_params->format = TIME_PRINT_ISO8601; + } + ret = keymgr_list_trash(&kctx, zone_name, list_params); + print_ok_on_succes = false; } else if (same_command(argv[1], "ds", false) || same_command(argv[1], "dnskey", false)) { int (*generate_rr)(const knot_dname_t *, const knot_kasp_key_t *) = keymgr_generate_dnskey; if (same_command(argv[1], "ds", false)) {