Commit d44d2b82 authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman

dnssec: refactored KSK flag; refactored zone-keys CSK handling, add CSK flag to KASP

parent 43389b1b
......@@ -233,6 +233,7 @@ static int serialize_key_params(const key_params_t *params, const knot_dname_t *
uint8_t flags = 0x02;
flags |= (params->is_ksk ? 0x01 : 0);
flags |= (params->is_pub_only ? 0x04 : 0);
flags |= (params->is_csk ? 0x08 : 0);
wire_ctx_write_u8(&wire, flags);
wire_ctx_write_u64(&wire, (uint64_t)params->timing.created);
wire_ctx_write_u64(&wire, (uint64_t)params->timing.pre_active);
......@@ -274,6 +275,10 @@ static int deserialize_key_params(key_params_t *params, const knot_db_val_t *key
uint8_t isksk_plus_flags = wire_ctx_read_u8(&wire);
params->is_ksk = ((isksk_plus_flags & (uint8_t)0x01) != (uint8_t)0x00);
params->is_pub_only = ((isksk_plus_flags & (uint8_t)0x04) != (uint8_t)0x00);
params->is_csk = ((isksk_plus_flags & (uint8_t)0x08) != (uint8_t)0x00);
if (params->is_csk && !params->is_ksk) {
return KNOT_EMALF;
}
if ((isksk_plus_flags & (uint8_t)0x02) != (uint8_t)0x00) {
params->timing.created = (knot_time_t)wire_ctx_read_u64(&wire);
params->timing.pre_active = (knot_time_t)wire_ctx_read_u64(&wire);
......
......@@ -98,6 +98,9 @@ static int params2kaspkey(const knot_dname_t *dname, key_params_t *params,
key->timing = params->timing;
key->is_pub_only = params->is_pub_only;
assert(params->is_ksk || !params->is_csk);
key->is_ksk = params->is_ksk;
key->is_zsk = (params->is_csk || !params->is_ksk);
return KNOT_EOK;
}
......@@ -111,6 +114,8 @@ static void kaspkey2params(knot_kasp_key_t *key, key_params_t *params)
dnssec_key_get_pubkey(key->key, &params->public_key);
params->algorithm = dnssec_key_get_algorithm(key->key);
params->is_ksk = dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_KSK;
assert(params->is_ksk == key->is_ksk);
params->is_csk = (key->is_ksk && key->is_zsk);
params->timing = key->timing;
params->is_pub_only = key->is_pub_only;
}
......
......@@ -42,6 +42,7 @@ typedef struct {
typedef struct {
char *id;
bool is_ksk;
bool is_csk;
bool is_pub_only;
uint16_t keytag;
uint8_t algorithm;
......@@ -57,6 +58,8 @@ typedef struct {
dnssec_key_t *key; /*!< Instance of the key. */
knot_kasp_key_timing_t timing; /*!< Key timing information. */
bool is_pub_only;
bool is_ksk;
bool is_zsk;
} knot_kasp_key_t;
/*!
......
......@@ -78,12 +78,12 @@ static knot_kasp_key_t *key_get_by_id(kdnssec_ctx_t *ctx, const char *keyid)
return NULL;
}
static int generate_key(kdnssec_ctx_t *ctx, bool ksk, knot_time_t when_active, bool pre_active)
static int generate_key(kdnssec_ctx_t *ctx, bool ksk, bool zsk, knot_time_t when_active, bool pre_active)
{
assert(!pre_active || when_active == 0);
knot_kasp_key_t *key = NULL;
int ret = kdnssec_generate_key(ctx, ksk, &key);
int ret = kdnssec_generate_key(ctx, ksk, zsk, &key);
if (ret != KNOT_EOK) {
return ret;
}
......@@ -98,7 +98,7 @@ static int generate_key(kdnssec_ctx_t *ctx, bool ksk, knot_time_t when_active, b
return KNOT_EOK;
}
static int share_or_generate_key(kdnssec_ctx_t *ctx, bool ksk, knot_time_t when_active, bool pre_active)
static int share_or_generate_key(kdnssec_ctx_t *ctx, bool ksk, bool zsk, knot_time_t when_active, bool pre_active)
{
assert(!pre_active || when_active == 0);
......@@ -118,7 +118,7 @@ static int share_or_generate_key(kdnssec_ctx_t *ctx, bool ksk, knot_time_t when_
// if we already have the policy-last key, we have to generate new one
if (ret == KNOT_ENOENT || key_id_present(ctx, borrow_key, DNSKEY_FLAGS_KSK)) {
knot_kasp_key_t *key = NULL;
ret = kdnssec_generate_key(ctx, ksk, &key);
ret = kdnssec_generate_key(ctx, ksk, zsk, &key);
if (ret != KNOT_EOK) {
return ret;
}
......@@ -180,7 +180,6 @@ static bool running_rollover(const kdnssec_ctx_t *ctx)
for (size_t i = 0; i < ctx->zone->num_keys; i++) {
knot_kasp_key_t *key = &ctx->zone->keys[i];
bool isksk = (dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_KSK);
switch (get_key_state(key, ctx->now)) {
case DNSSEC_KEY_STATE_PRE_ACTIVE:
res = true;
......@@ -189,10 +188,10 @@ static bool running_rollover(const kdnssec_ctx_t *ctx)
res = (res || !key->is_pub_only);
break;
case DNSSEC_KEY_STATE_READY:
ready_ksk = (ready_ksk || isksk);
ready_ksk = (ready_ksk || key->is_ksk);
break;
case DNSSEC_KEY_STATE_ACTIVE:
active_ksk = (active_ksk || isksk);
active_ksk = (active_ksk || key->is_ksk);
break;
case DNSSEC_KEY_STATE_RETIRE_ACTIVE:
case DNSSEC_KEY_STATE_POST_ACTIVE:
......@@ -337,8 +336,7 @@ static roll_action_t next_action(kdnssec_ctx_t *ctx)
if (key->is_pub_only) {
continue;
}
bool isksk = (dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_KSK);
if (isksk) {
if (key->is_ksk) {
switch (get_key_state(key, ctx->now)) {
case DNSSEC_KEY_STATE_PRE_ACTIVE:
keytime = alg_publish_time(key->timing.pre_active, ctx);
......@@ -419,7 +417,7 @@ static roll_action_t next_action(kdnssec_ctx_t *ctx)
}
if (knot_time_cmp(keytime, res.time) < 0) {
res.key = key;
res.ksk = isksk;
res.ksk = key->is_ksk;
res.time = keytime;
res.type = restype;
}
......@@ -431,13 +429,12 @@ static roll_action_t next_action(kdnssec_ctx_t *ctx)
static int submit_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *newkey)
{
assert(get_key_state(newkey, ctx->now) == DNSSEC_KEY_STATE_PUBLISHED);
assert(dnssec_key_get_flags(newkey->key) == DNSKEY_FLAGS_KSK);
assert(newkey->is_ksk);
// pushing from READY into ACTIVE decreases the other key's cds_priority
for (size_t i = 0; i < ctx->zone->num_keys; i++) {
knot_kasp_key_t *key = &ctx->zone->keys[i];
if (dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_KSK &&
get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_READY) {
if (key->is_ksk && get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_READY) {
key->timing.active = ctx->now;
}
}
......@@ -448,20 +445,17 @@ static int submit_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *newkey)
static int exec_new_signatures(kdnssec_ctx_t *ctx, knot_kasp_key_t *newkey)
{
uint16_t kskflag = dnssec_key_get_flags(newkey->key);
if (kskflag == DNSKEY_FLAGS_KSK) {
if (newkey->is_ksk) {
log_zone_notice(ctx->zone->dname, "DNSSEC, KSK submission, confirmed");
}
for (size_t i = 0; i < ctx->zone->num_keys; i++) {
knot_kasp_key_t *key = &ctx->zone->keys[i];
uint16_t keyflags = dnssec_key_get_flags(key->key);
key_state_t keystate = get_key_state(key, ctx->now);
uint8_t keyalg = dnssec_key_get_algorithm(key->key);
if (keyflags == kskflag && keystate == DNSSEC_KEY_STATE_ACTIVE) {
if (keyflags == DNSKEY_FLAGS_KSK ||
keyalg != dnssec_key_get_algorithm(newkey->key)) {
if (((newkey->is_ksk && key->is_ksk) || (newkey->is_zsk && key->is_zsk))
&& keystate == DNSSEC_KEY_STATE_ACTIVE) {
if (key->is_ksk || keyalg != dnssec_key_get_algorithm(newkey->key)) {
key->timing.retire_active = ctx->now;
} else {
key->timing.retire = ctx->now;
......@@ -469,7 +463,7 @@ static int exec_new_signatures(kdnssec_ctx_t *ctx, knot_kasp_key_t *newkey)
}
}
if (kskflag == DNSKEY_FLAGS_KSK) {
if (newkey->is_ksk) {
assert(get_key_state(newkey, ctx->now) == DNSSEC_KEY_STATE_READY);
} else {
assert(get_key_state(newkey, ctx->now) == DNSSEC_KEY_STATE_PUBLISHED);
......@@ -494,8 +488,7 @@ static int exec_ksk_retire(kdnssec_ctx_t *ctx, knot_kasp_key_t *key)
for (size_t i = 0; i < ctx->zone->num_keys; i++) {
knot_kasp_key_t *key = &ctx->zone->keys[i];
if (dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_ZSK &&
get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_RETIRE_ACTIVE) {
if (key->is_zsk && get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_RETIRE_ACTIVE) {
alg_rollover = true;
alg_rollover_friend = key;
}
......@@ -535,9 +528,9 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_reschedule_t *resched
// generate initial keys if missing
if (!key_present(ctx, DNSKEY_FLAGS_KSK)) {
if (ctx->policy->ksk_shared) {
ret = share_or_generate_key(ctx, true, ctx->now, false);
ret = share_or_generate_key(ctx, true, ctx->policy->singe_type_signing, ctx->now, false);
} else {
ret = generate_key(ctx, true, ctx->now, false);
ret = generate_key(ctx, true, ctx->policy->singe_type_signing, ctx->now, false);
}
reschedule->plan_ds_query = true;
if (ret == KNOT_EOK) {
......@@ -546,7 +539,7 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_reschedule_t *resched
}
if (!ctx->policy->singe_type_signing && ret == KNOT_EOK &&
!key_present(ctx, DNSKEY_FLAGS_ZSK)) {
ret = generate_key(ctx, false, ctx->now, false);
ret = generate_key(ctx, false, true, ctx->now, false);
if (ret == KNOT_EOK) {
reschedule->keys_changed = true;
}
......@@ -555,12 +548,12 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_reschedule_t *resched
if (!algorithm_present(ctx,ctx->policy->algorithm) &&
!running_rollover(ctx) && ret == KNOT_EOK) {
if (ctx->policy->ksk_shared) {
ret = share_or_generate_key(ctx, true, 0, true);
ret = share_or_generate_key(ctx, true, ctx->policy->singe_type_signing, 0, true);
} else {
ret = generate_key(ctx, true, 0, true);
ret = generate_key(ctx, true, ctx->policy->singe_type_signing, 0, true);
}
if (!ctx->policy->singe_type_signing && ret == KNOT_EOK) {
ret = generate_key(ctx, false, 0, true);
ret = generate_key(ctx, false, true, 0, true);
}
log_zone_info(ctx->zone->dname, "DNSSEC, algorithm rollover started");
if (ret == KNOT_EOK) {
......@@ -579,9 +572,9 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_reschedule_t *resched
switch (next.type) {
case GENERATE:
if (next.ksk && ctx->policy->ksk_shared) {
ret = share_or_generate_key(ctx, next.ksk, 0, false);
ret = share_or_generate_key(ctx, true, ctx->policy->singe_type_signing, 0, false);
} else {
ret = generate_key(ctx, next.ksk, 0, false);
ret = generate_key(ctx, next.ksk, ctx->policy->singe_type_signing || !next.ksk, 0, false);
}
if (ret == KNOT_EOK) {
log_zone_info(ctx->zone->dname, "DNSSEC, %cSK rollover started",
......@@ -634,8 +627,7 @@ int knot_dnssec_ksk_sbm_confirm(kdnssec_ctx_t *ctx)
{
for (size_t i = 0; i < ctx->zone->num_keys; i++) {
knot_kasp_key_t *key = &ctx->zone->keys[i];
if (dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_KSK &&
get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_READY) {
if (key->is_ksk && get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_READY) {
int ret = exec_new_signatures(ctx, key);
if (ret == KNOT_EOK) {
ret = kdnssec_ctx_commit(ctx);
......@@ -652,7 +644,7 @@ bool zone_has_key_sbm(const kdnssec_ctx_t *ctx)
for (size_t i = 0; i < ctx->zone->num_keys; i++) {
knot_kasp_key_t *key = &ctx->zone->keys[i];
if (dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_KSK &&
if (key->is_ksk &&
(get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_READY ||
get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_ACTIVE)) {
return true;
......
......@@ -161,8 +161,7 @@ int knot_dnssec_zone_sign(zone_update_t *update,
goto done;
}
result = load_zone_keys(ctx.zone, ctx.keystore,
ctx.policy->nsec3_enabled, ctx.now, &keyset, true);
result = load_zone_keys(&ctx, &keyset, true);
if (result != KNOT_EOK) {
log_zone_error(zone_name, "DNSSEC, failed to load keys (%s)",
knot_strerror(result));
......@@ -247,8 +246,7 @@ int knot_dnssec_sign_update(zone_update_t *update, zone_sign_reschedule_t *resch
goto done;
}
result = load_zone_keys(ctx.zone, ctx.keystore,
ctx.policy->nsec3_enabled, ctx.now, &keyset, false);
result = load_zone_keys(&ctx, &keyset, false);
if (result != KNOT_EOK) {
log_zone_error(zone_name, "DNSSEC, failed to load keys (%s)",
knot_strerror(result));
......
This diff is collapsed.
......@@ -60,12 +60,13 @@ uint16_t dnskey_flags(bool is_ksk);
* \brief Generate new key, store all details in new kasp key structure.
*
* \param ctx kasp context
* \param ksk true = generate KSK, false = generate ZSK
* \param ksk true = generate KSK or CSK, false = generate ZSK
* \param zsk true = generate ZSK or CSK, false = generate KSK
* \param key_ptr output if KNOT_EOK: new pointer to generated key
*
* \return KNOT_E*
*/
int kdnssec_generate_key(kdnssec_ctx_t *ctx, bool ksk, knot_kasp_key_t **key_ptr);
int kdnssec_generate_key(kdnssec_ctx_t *ctx, bool ksk, bool zsk, knot_kasp_key_t **key_ptr);
/*!
* \brief Take a key from another zone (copying info, sharing privkey).
......@@ -95,17 +96,13 @@ int kdnssec_delete_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *key_ptr);
/*!
* \brief Load zone keys and init cryptographic context.
*
* \param zone KASP zone.
* \param store KASP key store.
* \param nsec3_enabled Zone uses NSEC3 for authenticated denial.
* \param now Current time.
* \param ctx Zone signing context.
* \param keyset_ptr Resulting zone keyset.
* \param verbose Print key summary into log.
*
* \return Error code, KNOT_EOK if successful.
*/
int load_zone_keys(knot_kasp_zone_t *zone, dnssec_keystore_t *store,
bool nsec3_enabled, knot_time_t now, zone_keyset_t *keyset_ptr,
bool verbose);
int load_zone_keys(kdnssec_ctx_t *ctx, zone_keyset_t *keyset_ptr, bool verbose);
/*!
* \brief Get zone keys by a keytag.
......
......@@ -219,7 +219,7 @@ int event_parent_ds_q(conf_t *conf, zone_t *zone)
}
zone_keyset_t keyset = { 0 };
ret = load_zone_keys(ctx.zone, ctx.keystore, false, ctx.now, &keyset, false);
ret = load_zone_keys(&ctx, &keyset, false);
if (ret != KNOT_EOK) {
kdnssec_ctx_deinit(&ctx);
return ret;
......
......@@ -154,7 +154,7 @@ int keymgr_generate_key(kdnssec_ctx_t *ctx, int argc, char *argv[])
}
knot_kasp_key_t *key = NULL;
int ret = kdnssec_generate_key(ctx, isksk, &key);
int ret = kdnssec_generate_key(ctx, isksk, !isksk, &key);
if (ret != KNOT_EOK) {
return ret;
}
......@@ -315,6 +315,8 @@ int keymgr_import_bind(kdnssec_ctx_t *ctx, const char *import_file, bool pub_onl
kkey->key = key;
kkey->timing = timing;
kkey->is_pub_only = pub_only;
kkey->is_ksk = (dnssec_key_get_flags(kkey->key) == DNSKEY_FLAGS_KSK);
kkey->is_zsk = !kkey->is_ksk;
// append to zone
ret = kasp_zone_append(ctx->zone, kkey);
......
......@@ -16,7 +16,7 @@ TEST_CASES = {
"rsa_now_ecdsa_future": True,
"rsa_ecdsa_roll": True,
"stss_ksk": True,
"stss_zsk": True,
# "stss_zsk": True, # No longer supported.
"stss_two_ksk": True,
"stss_rsa256_rsa512": True,
"rsa_split_ecdsa_stss": True,
......@@ -73,8 +73,6 @@ knot.key_gen("rsa_ecdsa_roll", ksk="true", created=GEN, publish=PAST, rea
knot.key_gen("rsa_ecdsa_roll", ksk="false", created=GEN, publish=FUTU, ready=PAST, active=PAST, retire=INF, remove=INF)
# STSS: KSK only
knot.key_gen("stss_ksk", ksk="true", created=GEN, publish=PAST, ready=PAST, active=PAST, retire=INF, remove=INF)
# STSS: ZSK only
knot.key_gen("stss_zsk", ksk="false", created=GEN, publish=PAST, ready=PAST, active=PAST, retire=INF, remove=INF)
# STSS: two KSKs
knot.key_gen("stss_two_ksk", ksk="true", created=GEN, publish=PAST, ready=PAST, active=PAST, retire=INF, remove=INF)
knot.key_gen("stss_two_ksk", ksk="true", created=GEN, publish=PAST, ready=PAST, active=PAST, retire=INF, remove=INF)
......
......@@ -8,24 +8,23 @@ from dnstest.test import Test
t = Test()
knot = t.server("knot")
zones = t.zone_rnd(5, dnssec=False, records=10)
zones = t.zone_rnd(4, dnssec=False, records=10)
t.link(zones, knot)
t.start()
# one KSK
knot.gen_key(zones[0], ksk=True, alg="RSASHA256", key_len="512")
# one ZSK
knot.gen_key(zones[1], ksk=False, alg="RSASHA512", key_len="1024")
# one ZSK no longer supported
# multiple KSKs
knot.gen_key(zones[2], ksk=True, alg="RSASHA512", key_len="1024")
knot.gen_key(zones[2], ksk=True, alg="RSASHA256", key_len="512")
knot.gen_key(zones[1], ksk=True, alg="RSASHA512", key_len="1024")
knot.gen_key(zones[1], ksk=True, alg="RSASHA256", key_len="512")
# different algorithms: KSK+ZSK pair, one ZSK
knot.gen_key(zones[3], ksk=True, alg="RSASHA256", key_len="1024")
knot.gen_key(zones[3], ksk=False, alg="RSASHA256", key_len="1024")
knot.gen_key(zones[3], ksk=False, alg="RSASHA512", key_len="1024")
# different algorithms: KSK+ZSK pair, one KSK
knot.gen_key(zones[2], ksk=True, alg="RSASHA256", key_len="1024")
knot.gen_key(zones[2], ksk=False, alg="RSASHA256", key_len="1024")
knot.gen_key(zones[2], ksk=True, alg="RSASHA512", key_len="1024")
for zone in zones[:-1]:
knot.dnssec(zone).enable = True
......
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