kaspdb: list keys in the "trash bin"

This commit is contained in:
David Vašek 2026-03-09 15:35:56 +01:00
parent 1138131171
commit da5c386dc0
6 changed files with 88 additions and 15 deletions

View file

@ -239,6 +239,25 @@ static MDB_val trash_serialize(const key_params_t *params,
params->keytag, params->algorithm, flags);
}
// For trash keys, timers in key_params_t are used as follows:
// params->timing.created -> deleted, i.e. time when the key has been moved to the trash bin
// params->timing.remove -> discard, i.e. time when the key will be discarded from the trash bin
static bool trash_deserialize(const MDB_val *val, key_params_t *params)
{
uint8_t flags;
if (knot_lmdb_unmake_key(val->mv_data, val->mv_size, "LLHBB",
&params->timing.remove, &params->timing.created,
&params->keytag, &params->algorithm, &flags)) {
bool flags_ok = flags_deserialize(params, flags);
if (flags_ok && (params->is_ksk || !params->is_csk)) {
return true;
}
}
return false;
}
static key_params_t *txn2params(knot_lmdb_txn_t *txn)
{
key_params_t *p = calloc(1, sizeof(*p));
@ -256,14 +275,62 @@ static key_params_t *txn2params(knot_lmdb_txn_t *txn)
return p;
}
int kasp_db_list_keys(knot_lmdb_db_t *db, const knot_dname_t *zone_name, list_t *dst)
static key_params_t *txn2params_trash(knot_lmdb_txn_t *txn, const knot_dname_t *zone_name)
{
const uint8_t kclass;
const char *kid;
const knot_dname_t *kdname;
if (!knot_lmdb_unmake_key(txn->cur_key.mv_data, txn->cur_key.mv_size,
"BSN", &kclass, &kid, &kdname)) {
txn->ret = KNOT_EMALF;
return NULL;
}
assert(kclass == KASPDBKEY_TRASH);
if (zone_name != NULL && knot_dname_cmp(zone_name, kdname)) {
// Not an error, just skip this key.
return NULL;
}
key_params_t *p;
char *id = NULL;
knot_dname_t *dname = NULL;
if ((p = calloc(1, sizeof(*p))) == NULL ||
(id = strdup(kid)) == NULL ||
(dname = knot_dname_copy(kdname, NULL)) == NULL) {
txn->ret = KNOT_ENOMEM;
goto fail;
}
p->id = id;
p->dname = dname;
if (!trash_deserialize(&txn->cur_val, p)) {
txn->ret = KNOT_EMALF;
goto fail;
}
return p;
fail:
free(p);
free(id);
free(dname);
return NULL;
}
int kasp_db_list_keys(knot_lmdb_db_t *db, const knot_dname_t *zone_name, list_t *dst,
bool trash)
{
init_list(dst);
knot_lmdb_txn_t txn = { 0 };
MDB_val prefix = make_key_str(KASPDBKEY_PARAMS, zone_name, NULL);
MDB_val prefix = trash ? knot_lmdb_make_key("B", KASPDBKEY_TRASH) :
make_key_str(KASPDBKEY_PARAMS, zone_name, NULL);
knot_lmdb_begin(db, &txn, false);
knot_lmdb_foreach(&txn, &prefix) {
key_params_t *p = txn2params(&txn);
key_params_t *p;
p = trash ? txn2params_trash(&txn, zone_name) :
txn2params(&txn);
if (p != NULL) {
ptrlist_add(dst, p, NULL);
}

View file

@ -22,15 +22,19 @@ typedef enum { // the enum values MUST match those from keyclass_t !!
} kaspdb_serial_t;
/*!
* \brief For given zone, list all keys (their IDs) belonging to it.
* \brief For given zone, list all keys (their IDs) belonging to it,
* or optionally list trashed keys instead.
*
* \param db KASP db
* \param zone_name name of the zone in question
* if NULL for trashed keys, list trashed keys belonging to any zone
* \param dst output if KNOT_EOK: ptrlist of keys' params
* \param trash if false, list all valid keys, if true, list all trashed keys
*
* \return KNOT_E* (KNOT_ENOENT if no keys)
*/
int kasp_db_list_keys(knot_lmdb_db_t *db, const knot_dname_t *zone_name, list_t *dst);
int kasp_db_list_keys(knot_lmdb_db_t *db, const knot_dname_t *zone_name, list_t *dst,
bool trash);
/*!
* \brief Obtain the algorithm of a key.

View file

@ -178,7 +178,7 @@ int kasp_zone_load(knot_kasp_zone_t *zone,
list_t key_params;
init_list(&key_params);
int ret = kasp_db_list_keys(kdb, zone_name, &key_params);
int ret = kasp_db_list_keys(kdb, zone_name, &key_params, false);
if (ret == KNOT_ENOENT) {
zone->keys = NULL;
zone->num_keys = 0;
@ -310,8 +310,9 @@ void free_key_params(key_params_t *parm)
{
if (parm != NULL) {
free(parm->id);
free(parm->dname);
dnssec_binary_free(&parm->public_key);
memset(parm, 0 , sizeof(*parm));
memset(parm, 0, sizeof(*parm));
}
}

View file

@ -24,7 +24,7 @@ typedef struct {
knot_time_t retire_active; /*!< Still active, but obsoleted. */
knot_time_t retire; /*!< End of RRSIG records generating. */
knot_time_t post_active; /*!< Still signing with old algorithm, not published. */
knot_time_t revoke; /*!< RFC 5011 state of KSK with 'revoked' flag and signed by self. */
knot_time_t revoke; /*!< RFC 5011 state of KSK with 'revoked' flag and signed by self. */
knot_time_t remove; /*!< Time of DNSKEY record removal. */
} knot_kasp_key_timing_t;
@ -33,6 +33,7 @@ typedef struct {
*/
typedef struct {
char *id;
knot_dname_t *dname; /*!< Zone that was using the key. Relevant for trash keys only. */
bool is_ksk;
bool is_csk;
bool is_pub_only;

View file

@ -399,7 +399,7 @@ static int backup_keystore(conf_t *conf, zone_t *zone, zone_backup_ctx_t *ctx)
list_t key_params;
init_list(&key_params);
ret = kasp_db_list_keys(zone_kaspdb(zone), zone->name, &key_params);
ret = kasp_db_list_keys(zone_kaspdb(zone), zone->name, &key_params, false);
ret = (ret == KNOT_ENOENT ? KNOT_EOK : ret);
if (ret != KNOT_EOK) {
LOG_FAIL("keystore list");

View file

@ -83,7 +83,7 @@ int main(int argc, char *argv[])
ret = kasp_db_add_key(db, zone1, &params1);
is_int(KNOT_EOK, ret, "kasp_db: add key 1 eok");
ret = kasp_db_list_keys(db, zone1, &l);
ret = kasp_db_list_keys(db, zone1, &l, false);
is_int(KNOT_EOK, ret, "kasp_db: list keys 1 eok");
is_int(1, list_size(&l), "kasp_db: list keys reports one key 1");
params = ((ptrnode_t *)HEAD(l))->d;
@ -91,7 +91,7 @@ int main(int argc, char *argv[])
free_params
ptrlist_deep_free(&l, NULL);
ret = kasp_db_list_keys(db, zone2, &l);
ret = kasp_db_list_keys(db, zone2, &l, false);
is_int(KNOT_ENOENT, ret, "kasp_db: list keys 1 enoent");
is_int(0, list_size(&l), "kasp_db: list keys reports no keys 1");
ptrlist_deep_free(&l, NULL);
@ -99,7 +99,7 @@ int main(int argc, char *argv[])
ret = kasp_db_share_key(db, zone1, zone2, params1.id);
is_int(KNOT_EOK, ret, "kasp_db: share key eok");
ret = kasp_db_list_keys(db, zone2, &l);
ret = kasp_db_list_keys(db, zone2, &l, false);
is_int(KNOT_EOK, ret, "kasp_db: list keys 3 eok");
is_int(1, list_size(&l), "kasp_db: list keys reports one key 2");
params = ((ptrnode_t *)HEAD(l))->d;
@ -109,7 +109,7 @@ int main(int argc, char *argv[])
ret = kasp_db_add_key(db, zone2, &params2);
is_int(KNOT_EOK, ret, "kasp_db: add key 2 eok");
ret = kasp_db_list_keys(db, zone2, &l);
ret = kasp_db_list_keys(db, zone2, &l, false);
is_int(KNOT_EOK, ret, "kasp_db: list keys 4 eok");
is_int(2, list_size(&l), "kasp_db: list keys reports two keys 1");
params = ((ptrnode_t *)TAIL(l))->d;
@ -122,7 +122,7 @@ int main(int argc, char *argv[])
ret = kasp_db_delete_key(db, zone1, params1.id, 0, &ignore);
is_int(KNOT_EOK, ret, "kasp_db: delete key 1 eok");
ret = kasp_db_list_keys(db, zone1, &l);
ret = kasp_db_list_keys(db, zone1, &l, false);
is_int(KNOT_ENOENT, ret, "kasp_db: list keys 2 enoent");
is_int(list_size(&l), 0, "kasp_db: list keys reports no keys 2");
ptrlist_deep_free(&l, NULL);
@ -147,7 +147,7 @@ int main(int argc, char *argv[])
ret = kasp_db_delete_all(db, zone2);
is_int(KNOT_EOK, ret, "kasp_db: delete all");
ret = kasp_db_list_keys(db, zone2, &l);
ret = kasp_db_list_keys(db, zone2, &l, false);
is_int(KNOT_EOK, ret, "kasp_db: do not delete keys");
is_int(2, list_size(&l), "kasp_db: list keys reports two keys 2");
params = ((ptrnode_t *)TAIL(l))->d;