]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
offline KSK: major redesign: KSR (only ZSKs) and SKR (DNSKEY, CDS, RRSIG)
authorLibor Peltan <libcha.p@gmail.com>
Wed, 19 Sep 2018 15:30:05 +0000 (17:30 +0200)
committerLibor Peltan <libor.peltan@nic.cz>
Mon, 5 Nov 2018 09:49:33 +0000 (10:49 +0100)
20 files changed:
doc/man/knot.conf.5in
doc/operation.rst
doc/reference.rst
src/knot/conf/schema.c
src/knot/conf/schema.h
src/knot/dnssec/context.c
src/knot/dnssec/context.h
src/knot/dnssec/kasp/kasp_db.c
src/knot/dnssec/kasp/kasp_db.h
src/knot/dnssec/kasp/policy.h
src/knot/dnssec/key-events.c
src/knot/dnssec/zone-events.c
src/knot/dnssec/zone-keys.c
src/knot/dnssec/zone-sign.c
src/knot/dnssec/zone-sign.h
src/knot/journal/serialization.c
src/utils/keymgr/offline_ksk.c
tests-extra/tests/dnssec/offline_ksk/test.py [deleted file]
tests-extra/tests/dnssec/offline_ksk2/test.py
tests-extra/tools/dnstest/server.py

index cf003a2923c752d65107528db130badbbe7dd0bd..4b651beba3bcccd7797b625831c0d4a16853b846 100644 (file)
@@ -620,6 +620,7 @@ policy:
     nsec3\-salt\-lifetime: TIME
     ksk\-submission: submission_id
     cds\-cdnskey\-publish: none | delete\-dnssec | rollover | always
+    offline\-ksk: BOOL
 .ft P
 .fi
 .UNINDENT
@@ -822,6 +823,11 @@ Possible values:
 .UNINDENT
 .sp
 \fIDefault:\fP always
+.SS offline\-ksk
+.sp
+Specifies if Offline KSK feature is enabled.
+.sp
+\fIDefault:\fP off
 .SH REMOTE SECTION
 .sp
 Definitions of remote servers for outgoing connections (source of a zone
index 7d6c68acf81f838f230ebb09c2e14ad8a8019a38..1a9040e678ccb43f451371d4be165916de706e17 100644 (file)
@@ -697,24 +697,23 @@ human-readable.
 
 For the "ZSK side" (i.e. the operator of the DNS server), the pre-requirements are
 similar to pervious case: proper DNSSEC configuration with :ref:`zsk-lifetime <policy_zsk-lifetime>`
-but :ref:`manual <policy_manual>`, a complete KASP db with the public part of the KSK
-(or multiple KSKs if in the middle of a rollover), but without its private part.
+but :ref:`manual <policy_manual>`, a complete KASP db with just ZSKs. Also
+:ref:`offline-ksk <policy_offline-ksk>` must be enabled.
 
 For the "KSK side" (i.e. the operator of the KSK signer), the pre-requirements are
 equal Knot configuration (at least the :ref:`Policy section` must be identical) and a KASP db
-with the KSK(s). The timers for the KSKs must be identical on both sides! The ZSKs are not
-necessary here, but their public parts might be in the KASP db too.
+with the KSK(s).
 
 The first step for the "ZSK side" is the same as previously: ``keymgr pregenerate``. Then,
 the operator shall export the public parts of the future ZSKs (in facts in the form of
-complete future DNSKEY records) by calling ``keymgr generate-ksr``. The output
+future DNSKEY records) by calling ``keymgr generate-ksr``. The output
 (called Key Signing Request; perhaps redirected to a file) shall be then sent to the
 "KSK side" e.g. via e-mail.
 
 The third step is done by "KSK side" by using the command ``keymgr sign-ksr`` with
-the KSR file as the parameter. This signs all the future forms of DNSKEY record,
-creating the future RRSIGs, which are again printed on output (and called Signed Key
-Response). This shall be sent back to "ZSK side".
+the KSR file as the parameter. This completes and signs all the future forms of DNSKEY record,
+creating the future RRSIGs (adding also CDNSKEYs and CDSs), which are again printed on output
+(and called Signed Key Response). This shall be sent back to "ZSK side".
 
 The last step is importing the signatures from SKR to the KASP db for later use,
 this is done by ``keymgr import-skr``, followed by (as previously) ``knotc zone-resign``
index 93bca65600eb99285d914aa0c7ed787af2de7c44..f57633cb6f324f3bf6cd4f9cc282896c3815ba9c 100644 (file)
@@ -684,6 +684,7 @@ DNSSEC policy configuration.
      nsec3-salt-lifetime: TIME
      ksk-submission: submission_id
      cds-cdnskey-publish: none | delete-dnssec | rollover | always
+     offline-ksk: BOOL
 
 .. _policy_id:
 
@@ -924,6 +925,15 @@ Possible values:
 
 *Default:* always
 
+.. _policy_offline-ksk:
+
+offline-ksk
+-----------
+
+Specifies if Offline KSK feature is enabled.
+
+*Default:* off
+
 .. _Remote section:
 
 Remote section
index 829c83ed9af54e3e2e8dc8332731cf51341e2665..df21a966e54f43ebac908ddfa0db3fd3a78988a4 100644 (file)
@@ -268,6 +268,7 @@ static const yp_item_t desc_policy[] = {
        { C_KSK_SBM,             YP_TREF,  YP_VREF = { C_SBM }, CONF_IO_FRLD_ZONES,
                                           { check_ref } },
        { C_CHILD_RECORDS,       YP_TOPT,  YP_VOPT = { child_record, CHILD_RECORDS_ALWAYS } },
+       { C_OFFLINE_KSK,         YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES },
        { C_COMMENT,             YP_TSTR,  YP_VNONE },
        { NULL }
 };
index 5725ad8146307130f277cf22c78ede8bc33ad6c5..23fe0cc4aa43589dda1f9b7c148035a177fff9f5 100644 (file)
@@ -81,6 +81,7 @@
 #define C_NSEC3_SALT_LEN       "\x11""nsec3-salt-length"
 #define C_NSEC3_SALT_LIFETIME  "\x13""nsec3-salt-lifetime"
 #define C_NSID                 "\x04""nsid"
+#define C_OFFLINE_KSK          "\x0B""offline-ksk"
 #define C_PARENT               "\x06""parent"
 #define C_PIDFILE              "\x07""pidfile"
 #define C_POLICY               "\x06""policy"
index ed1429f4dbc22c2465dd24dc21e6703e82a668d3..668639903666d76e30b165ce1ae092d09f62eb6a 100644 (file)
@@ -112,6 +112,9 @@ static void policy_load(knot_kasp_policy_t *policy, conf_val_t *id)
                        conf_val_next(&val);
                }
        }
+
+       val = conf_id_get(conf(), C_POLICY, C_OFFLINE_KSK, id);
+       policy->offline_ksk = conf_bool(&val);
 }
 
 int kdnssec_ctx_init(conf_t *conf, kdnssec_ctx_t *ctx, const knot_dname_t *zone_name,
@@ -209,6 +212,7 @@ void kdnssec_ctx_deinit(kdnssec_ctx_t *ctx)
                }
                free(ctx->policy);
        }
+       knot_rrset_free(ctx->offline_rrsig, NULL);
        dnssec_keystore_deinit(ctx->keystore);
        kasp_zone_free(&ctx->zone);
        free(ctx->kasp_zone_path);
index 795c1235fbbe4c4f2fbe59ec78dfe635d6b99d7c..560b449ffc67b8fb1c030a35560e1484661e1b9f 100644 (file)
@@ -40,6 +40,8 @@ typedef struct {
        bool rrsig_drop_existing;
        bool keep_deleted_keys;
        bool rollover_only_zsk;
+
+       knot_rrset_t *offline_rrsig;
 } kdnssec_ctx_t;
 
 /*!
index f96aea3ef864431afa6b29e16858604868cb377b..e15cc5eb50470434c993733c285e6a06a0eaf0cd 100644 (file)
@@ -757,16 +757,19 @@ static void for_time2string(char str[21], knot_time_t t)
        snprintf(str, 21, "%020lu", t);
 }
 
-int kasp_db_store_offline_rrsig(kasp_db_t *db, knot_time_t for_time, const knot_rrset_t *rrsig)
+int kasp_db_store_offline_rrsig(kasp_db_t *db, knot_time_t for_time, const knot_rrset_t *rrsig, const knot_rrset_t *dnskey,
+                                const knot_rrset_t *cdnskey, const knot_rrset_t *cds)
 {
-       if (db == NULL || rrsig == NULL || rrsig->type != KNOT_RRTYPE_RRSIG) {
+       if (db == NULL || rrsig == NULL || rrsig->type != KNOT_RRTYPE_RRSIG || dnskey == NULL || dnskey->type != KNOT_RRTYPE_DNSKEY ||
+           cdnskey == NULL || cdnskey->type != KNOT_RRTYPE_CDNSKEY || cds == NULL || cds->type != KNOT_RRTYPE_CDS) {
                return KNOT_EINVAL;
        }
 
        char for_time_str[21];
        for_time2string(for_time_str, for_time);
        knot_db_val_t key = make_key(KASPDBKEY_OFFLINE_RRSIG, rrsig->owner, for_time_str), val;
-       val.len = rrset_serialized_size(rrsig);
+       val.len = rrset_serialized_size(rrsig) + rrset_serialized_size(dnskey) +
+                 rrset_serialized_size(cdnskey) + rrset_serialized_size(cds);
        val.data = malloc(val.len);
        if (val.data == NULL) {
                free_key(&key);
@@ -775,6 +778,15 @@ int kasp_db_store_offline_rrsig(kasp_db_t *db, knot_time_t for_time, const knot_
        with_txn(KEYS_RW, NULL);
        wire_ctx_t wire = wire_ctx_init(val.data, val.len);
        ret = serialize_rrset(&wire, rrsig);
+       if (ret == KNOT_EOK) {
+               ret = serialize_rrset(&wire, dnskey);
+       }
+       if (ret == KNOT_EOK) {
+               ret = serialize_rrset(&wire, cdnskey);
+       }
+       if (ret == KNOT_EOK) {
+               ret = serialize_rrset(&wire, cds);
+       }
        if (ret == KNOT_EOK) {
                ret = db_api->insert(txn, &key, &val, 0);
        }
@@ -783,25 +795,56 @@ int kasp_db_store_offline_rrsig(kasp_db_t *db, knot_time_t for_time, const knot_
        return ret;
 }
 
-int kasp_db_load_offline_rrsig(kasp_db_t *db, const knot_dname_t *for_dname, knot_time_t for_time, knot_rrset_t *rrsig)
+int kasp_db_load_offline_rrsig(kasp_db_t *db, const knot_dname_t *for_dname, knot_time_t for_time, knot_time_t *next_time,
+                              knot_rrset_t *rrsig, knot_rrset_t *dnskey, knot_rrset_t *cdnskey, knot_rrset_t *cds)
 {
-       if (db == NULL || rrsig == NULL) {
+       if (db == NULL || rrsig == NULL || dnskey == NULL || cdnskey == NULL || cds == NULL) {
                return KNOT_EINVAL;
        }
 
        char for_time_str[21];
        for_time2string(for_time_str, for_time);
        with_txn(KEYS_RO, NULL);
-       knot_db_val_t key = make_key(KASPDBKEY_OFFLINE_RRSIG, for_dname, for_time_str), val;
-       ret = db_api->find(txn, &key, &val, KNOT_DB_LEQ);
-       if (ret == KNOT_EOK) {
-               wire_ctx_t wire = wire_ctx_init(val.data, val.len);
-               ret = deserialize_rrset(&wire, rrsig);
-               if (ret == KNOT_EOK && knot_dname_cmp(rrsig->owner, for_dname) != 0) {
-                       ret = KNOT_ENOENT;
+       knot_db_val_t search = make_key(KASPDBKEY_OFFLINE_RRSIG, for_dname, for_time_str), key, val;
+       knot_db_iter_t *it = db_api->iter_begin(txn, KNOT_DB_NOOP);
+       if (it == NULL) {
+               ret = KNOT_ERROR;
+               goto cleanup;
+       }
+       it = db_api->iter_seek(it, &search, KNOT_DB_LEQ);
+       if (it == NULL) {
+               ret = KNOT_ENOENT;
+               goto cleanup;
+       }
+       if (db_api->iter_key(it, &key) != KNOT_EOK || db_api->iter_val(it, &val) != KNOT_EOK) {
+               ret = KNOT_ERROR;
+               goto cleanup;
+       }
+       if (knot_dname_cmp((const knot_dname_t *)key.data + 1, rrsig->owner) != 0) {
+               ret = KNOT_ENOENT;
+               goto cleanup;
+       }
+       wire_ctx_t wire = wire_ctx_init(val.data, val.len);
+#define CHK_RET if (ret != KNOT_EOK) goto cleanup;
+       ret = deserialize_rrset(&wire, rrsig);
+       CHK_RET
+       ret = deserialize_rrset(&wire, dnskey);
+       CHK_RET
+       ret = deserialize_rrset(&wire, cdnskey);
+       CHK_RET
+       ret = deserialize_rrset(&wire, cds);
+       CHK_RET
+#undef CHK_RET
+       *next_time = 0;
+       if ((it = db_api->iter_next(it)) != NULL && db_api->iter_key(it, &key) == KNOT_EOK) {
+               const knot_dname_t *next_name = (const knot_dname_t *)key.data + 1;
+               if (knot_dname_cmp(next_name, rrsig->owner) == 0) {
+                       *next_time = atol((char *)key.data + 1 + knot_dname_size(next_name));
                }
        }
-       free_key(&key);
+cleanup:
+       db_api->iter_finish(it);
+       free_key(&search);
        with_txn_end(NULL);
        return ret;
 }
index d09be132bfd0cde0b598ee1ad5d441cb6cb15575..c022c8723205951b6d133671f1aebdbbd67436e3 100644 (file)
@@ -243,7 +243,8 @@ int kasp_db_list_zones(kasp_db_t *db, list_t *dst);
  *
  * \return KNOT_E*
  */
-int kasp_db_store_offline_rrsig(kasp_db_t *db, knot_time_t for_time, const knot_rrset_t *rrsig);
+int kasp_db_store_offline_rrsig(kasp_db_t *db, knot_time_t for_time, const knot_rrset_t *rrsig,
+                                const knot_rrset_t *dnskey, const knot_rrset_t *cdnskey, const knot_rrset_t *cds);
 
 /*!
  * \brief Load pregenerated RRSIG.
@@ -255,7 +256,8 @@ int kasp_db_store_offline_rrsig(kasp_db_t *db, knot_time_t for_time, const knot_
  *
  * \return KNOT_E*
  */
-int kasp_db_load_offline_rrsig(kasp_db_t *db, const knot_dname_t *for_dname, knot_time_t for_time, knot_rrset_t *rrsig);
+int kasp_db_load_offline_rrsig(kasp_db_t *db, const knot_dname_t *for_dname, knot_time_t for_time, knot_time_t *next_time,
+                               knot_rrset_t *rrsig, knot_rrset_t *dnskey, knot_rrset_t *cdnskey, knot_rrset_t *cds);
 
 /*!
  * \brief Delete pregenerated RRSIGs from beginning to the specified timestamp.
index 0628d71bee8fa0fe0a5ad15decece8e76e509d9e..f1374c53be9c8a8bb7755425cb5a912054553a98 100644 (file)
@@ -108,5 +108,6 @@ typedef struct {
        uint32_t ksk_sbm_check_interval;
        unsigned child_records_publish;
        parent_dynarray_t parents;
+       bool offline_ksk;
 } knot_kasp_policy_t;
 // TODO make the time parameters knot_timediff_t ??
index 2695993c9f9fe9b9d771e19469ba0d864aff9ae4..1b69c68464c082cc442f2251753798bdfa536f11 100644 (file)
@@ -584,12 +584,14 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_roll_flags_t flags,
        bool allowed_general_roll = ((flags & KEY_ROLL_ALLOW_KSK_ROLL) && (flags & KEY_ROLL_ALLOW_ZSK_ROLL));
        // generate initial keys if missing
        if (!key_present(ctx, true, false) && !key_present(ctx, true, true)) {
-               if (ctx->policy->ksk_shared) {
-                       ret = share_or_generate_key(ctx, GEN_KSK_FLAGS, ctx->now, false);
-               } else {
-                       ret = generate_key(ctx, GEN_KSK_FLAGS, ctx->now, false);
+               if (!ctx->rollover_only_zsk) {
+                       if (ctx->policy->ksk_shared) {
+                               ret = share_or_generate_key(ctx, GEN_KSK_FLAGS, ctx->now, false);
+                       } else {
+                               ret = generate_key(ctx, GEN_KSK_FLAGS, ctx->now, false);
+                       }
+                       reschedule->plan_ds_query = true;
                }
-               reschedule->plan_ds_query = true;
                if (ret == KNOT_EOK) {
                        reschedule->keys_changed = true;
                        if (!ctx->policy->singe_type_signing &&
index 01017791cf1c73664a411734223f111acdf5a5d8..bf6fc8e24eb0e7b073783e7bce1fb2ff375f7351 100644 (file)
@@ -170,7 +170,8 @@ int knot_dnssec_zone_sign(zone_update_t *update,
 
        log_zone_info(zone_name, "DNSSEC, signing started");
 
-       result = knot_zone_sign_update_dnskeys(update, &keyset, &ctx);
+       knot_time_t next_resign = 0;
+       result = knot_zone_sign_update_dnskeys(update, &keyset, &ctx, &next_resign);
        if (result != KNOT_EOK) {
                log_zone_error(zone_name, "DNSSEC, failed to update DNSKEY records (%s)",
                               knot_strerror(result));
@@ -217,7 +218,7 @@ int knot_dnssec_zone_sign(zone_update_t *update,
 
 done:
        if (result == KNOT_EOK) {
-               reschedule->next_sign = schedule_next(&ctx, &keyset, zone_expire);
+               reschedule->next_sign = schedule_next(&ctx, &keyset, knot_time_min(zone_expire, next_resign));
        }
 
        free_zone_keys(&keyset);
index 4c06804da22cf19dbab3acf3f082d4f5f47e67ff..826063051fcd50c61e017bd7cd7e76dd007238ae 100644 (file)
@@ -288,6 +288,12 @@ static int walk_algorithms(kdnssec_ctx_t *ctx, zone_keyset_t *keyset)
                case 15: // all keys ready for signing
                        have_active_alg = true;
                        break;
+               case 10:
+                       if (ctx->policy->offline_ksk) {
+                               have_active_alg = true;
+                               break;
+                       }
+                       // else FALLTHROUGH
                default:
                        return KNOT_DNSSEC_EMISSINGKEYTYPE;
                }
@@ -323,8 +329,6 @@ static int load_private_keys(dnssec_keystore_t *keystore, zone_keyset_t *keyset)
                case DNSSEC_EOK:
                case DNSSEC_KEY_ALREADY_PRESENT:
                        break;
-               case DNSSEC_ENOENT: // we hope that this is just offline KSK
-                       break;
                default:
                        return r;
                }
index d9e9488d9a2113c3380f5d5b028f6ef99f1fa365..5a03752e778519453929208f7c76a20d48d027d8 100644 (file)
@@ -277,28 +277,6 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered,
        return result;
 }
 
-static bool can_have_offline_rrsig(const knot_rrset_t *rr, const knot_dname_t *zone_apex)
-{
-       return (rr->type == KNOT_RRTYPE_DNSKEY && knot_dname_cmp(rr->owner, zone_apex) == 0);
-}
-
-static int load_offline_rrsig(const knot_rrset_t *covered,
-                               knot_rrset_t *rrsig,
-                               const kdnssec_ctx_t *ctx)
-{
-        knot_rrset_init_empty(rrsig);
-
-       if (!can_have_offline_rrsig(covered, ctx->zone->dname)) {
-               return KNOT_EOK;
-       }
-
-       int ret = kasp_db_load_offline_rrsig(*ctx->kasp_db, covered->owner, ctx->now, rrsig);
-       if (ret == KNOT_ENOENT) {
-               ret = KNOT_EOK;
-       }
-       return ret;
-}
-
 /*!
  * \brief Add missing RRSIGs into the changeset for adding.
  *
@@ -322,12 +300,14 @@ static int add_missing_rrsigs(const knot_rrset_t *covered,
        assert(zone_keys);
        assert(changeset);
 
-       knot_rrset_t to_add, offline_rrsigs;
+       int result = KNOT_EOK;
+       knot_rrset_t to_add;
        knot_rrset_init_empty(&to_add);
-       int result = load_offline_rrsig(covered, &offline_rrsigs, dnssec_ctx);
-       if (result != KNOT_EOK) {
-               log_zone_warning(dnssec_ctx->zone->dname, "DNSSEC, failed to load offline DNSKEY RRSIG (%s)",
-                                knot_strerror(result));
+
+       if (covered->type == KNOT_RRTYPE_DNSKEY &&
+           knot_dname_cmp(covered->owner, dnssec_ctx->zone->dname) == 0 &&
+           dnssec_ctx->offline_rrsig != NULL) {
+               return changeset_add_addition(changeset, dnssec_ctx->offline_rrsig, CHANGESET_CHECK);
        }
 
        for (int i = 0; i < zone_keys->count; i++) {
@@ -344,17 +324,6 @@ static int add_missing_rrsigs(const knot_rrset_t *covered,
                        to_add = create_empty_rrsigs_for(covered);
                }
 
-               uint16_t at_offline;
-               if (valid_signature_exists(covered, &offline_rrsigs, key->key, key->ctx, dnssec_ctx, &at_offline)) {
-                       log_zone_info(dnssec_ctx->zone->dname, "DNSSEC, using offline DNSKEY RRSIG");
-                       knot_rdata_t *offline_rd = knot_rdataset_at(&offline_rrsigs.rrs, at_offline);
-                       result = knot_rrset_add_rdata(&to_add, offline_rd->data, offline_rd->len, NULL);
-                       if (result != KNOT_EOK) {
-                               break;
-                       }
-                       continue;
-               }
-
                result = knot_sign_rrset(&to_add, covered, key->key, key->ctx,
                                         dnssec_ctx, NULL, expires_at);
                if (result != KNOT_EOK) {
@@ -367,7 +336,6 @@ static int add_missing_rrsigs(const knot_rrset_t *covered,
        }
 
        knot_rdataset_clear(&to_add.rrs, NULL);
-       knot_rrset_clear(&offline_rrsigs, NULL);
 
        return result;
 }
@@ -973,7 +941,8 @@ int knot_zone_sign_add_dnskeys(zone_keyset_t *zone_keys, const kdnssec_ctx_t *dn
 
 int knot_zone_sign_update_dnskeys(zone_update_t *update,
                                   zone_keyset_t *zone_keys,
-                                  const kdnssec_ctx_t *dnssec_ctx)
+                                  kdnssec_ctx_t *dnssec_ctx,
+                                  knot_time_t *next_resign)
 {
        if (update == NULL || zone_keys == NULL || dnssec_ctx == NULL) {
                return KNOT_EINVAL;
@@ -986,6 +955,7 @@ int knot_zone_sign_update_dnskeys(zone_update_t *update,
        knot_rrset_t *add_dnskeys = NULL;
        knot_rrset_t *add_cdnskeys = NULL;
        knot_rrset_t *add_cdss = NULL;
+       knot_rrset_t *add_rrsigs = NULL;
        uint32_t dnskey_ttl = dnssec_ctx->policy->dnskey_ttl;
        knot_rrset_t soa = node_rrset(apex, KNOT_RRTYPE_SOA);
        if (knot_rrset_empty(&soa)) {
@@ -1015,12 +985,25 @@ int knot_zone_sign_update_dnskeys(zone_update_t *update,
                                      0, NULL);
        add_cdss = knot_rrset_new(apex->owner, KNOT_RRTYPE_CDS, soa.rclass,
                                  0, NULL);
-       if (add_dnskeys == NULL || add_cdnskeys == NULL || add_cdss == NULL) {
+       add_rrsigs = knot_rrset_new(apex->owner, KNOT_RRTYPE_RRSIG, soa.rclass,
+                                   dnskey_ttl, NULL);
+       if (add_dnskeys == NULL || add_cdnskeys == NULL || add_cdss == NULL || add_rrsigs == NULL) {
                ret = KNOT_ENOMEM;
                CHECK_RET;
        }
 
-       ret = knot_zone_sign_add_dnskeys(zone_keys, dnssec_ctx, add_dnskeys, add_cdnskeys, add_cdss);
+       if (dnssec_ctx->policy->offline_ksk) {
+               ret = kasp_db_load_offline_rrsig(*dnssec_ctx->kasp_db, apex->owner, dnssec_ctx->now, next_resign,
+                                                add_rrsigs, add_dnskeys, add_cdnskeys, add_cdss);
+               if (ret == KNOT_EOK) {
+                       log_zone_info(dnssec_ctx->zone->dname, "DNSSEC, using offline DNSKEY RRSIG");
+               } else {
+                       log_zone_warning(dnssec_ctx->zone->dname, "DNSSEC, failed to load offline DNSKEY RRSIG (%s)",
+                                        knot_strerror(ret));
+               }
+       } else {
+               ret = knot_zone_sign_add_dnskeys(zone_keys, dnssec_ctx, add_dnskeys, add_cdnskeys, add_cdss);
+       }
        CHECK_RET;
 
        if (!knot_rrset_empty(add_cdnskeys)) {
@@ -1041,6 +1024,11 @@ int knot_zone_sign_update_dnskeys(zone_update_t *update,
                CHECK_RET;
        }
 
+       if (!knot_rrset_empty(add_rrsigs)) {
+               dnssec_ctx->offline_rrsig = add_rrsigs;
+               add_rrsigs = NULL; // prevent free
+       }
+
        ret = zone_update_apply_changeset(update, &ch);
 
 #undef CHECK_RET
@@ -1049,6 +1037,7 @@ cleanup:
        knot_rrset_free(add_dnskeys, NULL);
        knot_rrset_free(add_cdnskeys, NULL);
        knot_rrset_free(add_cdss, NULL);
+       knot_rrset_free(add_rrsigs, NULL);
        changeset_clear(&ch);
        return ret;
 }
index 4c6a23156979df79dced813911c8d9f8e611994b..38472baea4a59a5a48280cd644920466aadeab3c 100644 (file)
@@ -49,7 +49,8 @@ int knot_zone_sign_add_dnskeys(zone_keyset_t *zone_keys, const kdnssec_ctx_t *dn
  */
 int knot_zone_sign_update_dnskeys(zone_update_t *update,
                                   zone_keyset_t *zone_keys,
-                                  const kdnssec_ctx_t *dnssec_ctx);
+                                  kdnssec_ctx_t *dnssec_ctx,
+                                  knot_time_t *next_resign);
 
 /*!
  * \brief Check if key can be used to sign given RR.
index d764fe606cc49efa5ae15c3686d990d3fc528fe3..fd307111abe07ad1430cfe8ff1259ac9eba235a6 100644 (file)
@@ -429,6 +429,13 @@ int deserialize_rrset(wire_ctx_t *wire, knot_rrset_t *rrset)
        if (wire->error != KNOT_EOK) {
                return wire->error;
        }
+       if (rrset->owner != NULL) {
+               if (knot_dname_cmp(owner, rrset->owner) != 0) {
+                       knot_dname_free(owner, NULL);
+                       return KNOT_ESEMCHECK;
+               }
+               knot_rrset_clear(rrset, NULL);
+       }
        knot_rrset_init(rrset, owner, type, rclass, 0);
 
        for (size_t phase = 0; phase < rrcount && wire_ctx_available(wire) > 0; phase++) {
@@ -452,7 +459,7 @@ int deserialize_rrset(wire_ctx_t *wire, knot_rrset_t *rrset)
 
 size_t rrset_serialized_size(const knot_rrset_t *rrset)
 {
-       if (rrset == NULL || rrset->rrs.count == 0) {
+       if (rrset == NULL) {
                return 0;
        }
 
index d9d0b1fc851c3665f772bf0eb47f47a08c57ddb4..d62b37ac9ccf5c6486d7c9ccae3283e3ba572edb 100644 (file)
@@ -127,7 +127,7 @@ static int presign_once(kdnssec_ctx_t *ctx)
 
        // store it to KASP db
        assert(!knot_rrset_empty(rrsig));
-       ret = kasp_db_store_offline_rrsig(*ctx->kasp_db, ctx->now, rrsig);
+       ret = kasp_db_store_offline_rrsig(*ctx->kasp_db, ctx->now, rrsig, NULL, NULL, NULL); // TODO !
        if (ret != KNOT_EOK) {
                printf("store rrsig failed\n");
                goto done;
@@ -186,20 +186,41 @@ static int dump_rrset_to_buf(const knot_rrset_t *rrset, char **buf, size_t *buf_
 
 int keymgr_print_rrsig(kdnssec_ctx_t *ctx, knot_time_t when)
 {
-       knot_rrset_t rrsig = { 0 };
-       knot_rrset_init_empty(&rrsig);
-       int ret = kasp_db_load_offline_rrsig(*ctx->kasp_db, ctx->zone->dname, when, &rrsig);
+       knot_time_t next = 0;
+       knot_rrset_t rrsig = { 0 }, dnskey = { 0 }, cdnskey = { 0 }, cds = { 0 };
+       knot_rrset_init(&rrsig, knot_dname_copy(ctx->zone->dname, NULL),
+                       KNOT_RRTYPE_RRSIG, KNOT_CLASS_IN, ctx->policy->dnskey_ttl);
+       knot_rrset_init_empty(&dnskey);
+       knot_rrset_init_empty(&cdnskey);
+       knot_rrset_init_empty(&cds);
+       int ret = kasp_db_load_offline_rrsig(*ctx->kasp_db, ctx->zone->dname, when, &next, &rrsig, &dnskey, &cdnskey, &cds);
        if (ret == KNOT_EOK) {
                char *buf = NULL;
                size_t buf_size = 512;
                ret = dump_rrset_to_buf(&rrsig, &buf, &buf_size);
+               if (ret >= 0) {
+                       printf("%s", buf);
+                       ret = dump_rrset_to_buf(&dnskey, &buf, &buf_size);
+               }
+               if (ret >= 0) {
+                       printf("%s", buf);
+                       ret = dump_rrset_to_buf(&cdnskey, &buf, &buf_size);
+               }
+               if (ret >= 0) {
+                       printf("%s", buf);
+                       ret = dump_rrset_to_buf(&cds, &buf, &buf_size);
+               }
                if (ret >= 0) {
                        printf("%s", buf);
                        ret = KNOT_EOK;
                }
                free(buf);
+               printf("; next %lu\n", next);
        }
        knot_rrset_clear(&rrsig, NULL);
+       knot_rrset_clear(&dnskey, NULL);
+       knot_rrset_clear(&cdnskey, NULL);
+       knot_rrset_clear(&cds, NULL);
        return ret;
 }
 
@@ -227,7 +248,7 @@ static void print_generated_message()
        printf("generated on %s by KnotDNS %s\n", buf, VERSION);
 }
 
-static int ksr_once(kdnssec_ctx_t *ctx, char **buf, size_t *buf_size)
+static int ksr_once(kdnssec_ctx_t *ctx, char **buf, size_t *buf_size, knot_time_t *next_ksr)
 {
        knot_rrset_t *dnskey = NULL;
        zone_keyset_t keyset = { 0 };
@@ -243,6 +264,9 @@ static int ksr_once(kdnssec_ctx_t *ctx, char **buf, size_t *buf_size)
        }
 
 done:
+       if (ret == KNOT_EOK && next_ksr != NULL) {
+               *next_ksr = knot_get_next_zone_key_event(&keyset);
+       }
        knot_rrset_free(dnskey, NULL);
        free_zone_keys(&keyset);
        return ret;
@@ -255,11 +279,18 @@ int keymgr_print_ksr(kdnssec_ctx_t *ctx, knot_time_t upto)
        char *buf = NULL;
        size_t buf_size = 4096;
 
-       while (ret == KNOT_EOK && knot_time_cmp(next, upto) <= 0) {
+       while (ret == KNOT_EOK && knot_time_cmp(next, upto) < 0) {
                ctx->now = next;
-               ret = ksr_once(ctx, &buf, &buf_size);
-               next_resign(&next, ctx);
+               ret = ksr_once(ctx, &buf, &buf_size, &next);
        }
+       if (ret != KNOT_EOK) {
+               free(buf);
+               return ret;
+       }
+       ctx->now = upto;
+       // force end of period as a KSR timestamp
+       ret = ksr_once(ctx, &buf, &buf_size, NULL);
+
        printf(";; KeySigningRequest ");
        print_generated_message();
 
@@ -268,11 +299,15 @@ int keymgr_print_ksr(kdnssec_ctx_t *ctx, knot_time_t upto)
 }
 
 typedef struct {
-       knot_rrset_t *rr;
+       knot_rrset_t *dnskey;
+       knot_rrset_t *dnskey_prev;
+       knot_rrset_t *cdnskey;
+       knot_rrset_t *cds;
+       knot_rrset_t *rrsig;
        kdnssec_ctx_t *kctx;
 } ksr_sign_ctx_t;
 
-static int ksr_sign_dnskey(kdnssec_ctx_t *ctx, knot_rrset_t *dnskey)
+static int ksr_sign_dnskey(kdnssec_ctx_t *ctx, knot_rrset_t *zsk, knot_time_t *next_sign)
 {
        zone_keyset_t keyset = { 0 };
        char *buf = NULL;
@@ -281,11 +316,20 @@ static int ksr_sign_dnskey(kdnssec_ctx_t *ctx, knot_rrset_t *dnskey)
        if (ret != KNOT_EOK) {
                return ret;
        }
-       knot_rrset_t *rrsig = knot_rrset_new(ctx->zone->dname, KNOT_RRTYPE_RRSIG, KNOT_CLASS_IN, ctx->policy->dnskey_ttl, NULL);
-       if (rrsig == NULL) {
+       knot_rrset_t *dnskey = knot_rrset_copy(zsk, NULL);
+       knot_rrset_t *cdnskey = knot_rrset_new(zsk->owner, KNOT_RRTYPE_CDNSKEY, zsk->rclass, 0, NULL);
+       knot_rrset_t *cds = knot_rrset_new(zsk->owner, KNOT_RRTYPE_CDS, zsk->rclass, 0, NULL);
+       knot_rrset_t *rrsig = knot_rrset_new(zsk->owner, KNOT_RRTYPE_RRSIG, zsk->rclass, zsk->ttl, NULL);
+       if (dnskey == NULL || cdnskey == NULL || cds == NULL || rrsig == NULL) {
                ret = KNOT_ENOMEM;
                goto done;
        }
+
+       ret = knot_zone_sign_add_dnskeys(&keyset, ctx, dnskey, cdnskey, cds);
+       if (ret != KNOT_EOK) {
+               goto done;
+       }
+
        // no check if the KSK used for signing (in keyset) is contained in DNSKEY record being signed (in KSR) !
        for (int i = 0; i < keyset.count; i++) {
                zone_key_t *key = &keyset.keys[i];
@@ -296,49 +340,116 @@ static int ksr_sign_dnskey(kdnssec_ctx_t *ctx, knot_rrset_t *dnskey)
                        }
                }
        }
-       ret = dump_rrset_to_buf(rrsig, &buf, &buf_size);
+       printf(";;SKR ===========\n");
+       ret = dump_rrset_to_buf(dnskey, &buf, &buf_size);
+       if (ret >= 0) {
+               printf("%s", buf);
+               ret = dump_rrset_to_buf(cdnskey, &buf, &buf_size);
+       }
+       if (ret >= 0) {
+               printf("%s", buf);
+               ret = dump_rrset_to_buf(cds, &buf, &buf_size);
+       }
+       if (ret >= 0) {
+               printf("%s", buf);
+               ret = dump_rrset_to_buf(rrsig, &buf, &buf_size);
+       }
        if (ret >= 0) {
                buf[strlen(buf) - 1] = '\0'; // remove trailing newline
-               printf(";;SKR %lu %hu %d\n%s ; end SKR %lu\n", ctx->now, rrsig->rrs.count, ret, buf, ctx->now);
+               printf("%s ; end SKR %lu\n", buf, ctx->now);
                ret = KNOT_EOK;
        }
 
 done:
        free(buf);
+       knot_rrset_free(dnskey, NULL);
+       knot_rrset_free(cdnskey, NULL);
+       knot_rrset_free(cds, NULL);
        knot_rrset_free(rrsig, NULL);
+       if (ret == KNOT_EOK) {
+               *next_sign = knot_get_next_zone_key_event(&keyset);
+       }
        free_zone_keys(&keyset);
        return ret;
 }
 
+static int process_skr_between_ksrs(ksr_sign_ctx_t *ctx, knot_time_t next_ksr)
+{
+       static knot_time_t prev_ksr = 0;
+
+       assert((prev_ksr == 0 ? 1 : 0) == (knot_rrset_empty(ctx->dnskey_prev) ? 1 : 0));
+
+       if (!knot_rrset_empty(ctx->dnskey_prev)) {
+               for (knot_time_t inbetween_skr = prev_ksr; inbetween_skr < next_ksr; ) {
+                       ctx->kctx->now = inbetween_skr;
+                       int ret = ksr_sign_dnskey(ctx->kctx, ctx->dnskey_prev, &inbetween_skr);
+                       if (ret != KNOT_EOK) {
+                               return ret;
+                       }
+               }
+       }
+
+       // finally, do the "requested" SKR and copy ctx->dnskey into ct->rrsig
+       ctx->kctx->now = next_ksr;
+       int ret = ksr_sign_dnskey(ctx->kctx, ctx->dnskey, &prev_ksr);
+       if (ret != KNOT_EOK) {
+               return ret;
+       }
+       knot_rdataset_clear(&ctx->dnskey_prev->rrs, NULL);
+       ret = knot_rdataset_copy(&ctx->dnskey_prev->rrs, &ctx->dnskey->rrs, NULL);
+       return ret;
+}
+
 static void ksr_sign_once(zs_scanner_t *sc)
 {
        ksr_sign_ctx_t *ctx = sc->process.data;
 
-       sc->error.code = knot_rrset_add_rdata(ctx->rr, sc->r_data, sc->r_data_length, NULL);
-       ctx->rr->ttl = sc->r_ttl;
+       sc->error.code = knot_rrset_add_rdata(ctx->dnskey, sc->r_data, sc->r_data_length, NULL);
+       ctx->dnskey->ttl = sc->r_ttl;
 
        if (sc->error.code == KNOT_EOK && sc->buffer_length > 9 && strncmp((const char *)sc->buffer, " end KSR ", 9) == 0) {
-               ctx->kctx->now = atol((const char *)sc->buffer + 9);
-               sc->error.code = ksr_sign_dnskey(ctx->kctx, ctx->rr);
-               knot_rdataset_clear(&ctx->rr->rrs, NULL);
+               knot_time_t next_ksr = atol((const char *)sc->buffer + 9);
+               sc->error.code = process_skr_between_ksrs(ctx, next_ksr);
+               knot_rdataset_clear(&ctx->dnskey->rrs, NULL);
        }
 }
 
 static void skr_import_once(zs_scanner_t *sc)
 {
        ksr_sign_ctx_t *ctx = sc->process.data;
+       knot_rrset_t *to_add = NULL;
+       switch (sc->r_type) {
+       case KNOT_RRTYPE_DNSKEY:
+               to_add = ctx->dnskey;
+               break;
+       case KNOT_RRTYPE_CDNSKEY:
+               to_add = ctx->cdnskey;
+               break;
+       case KNOT_RRTYPE_CDS:
+               to_add = ctx->cds;
+               break;
+       case KNOT_RRTYPE_RRSIG:
+               to_add = ctx->rrsig;
+               break;
+       default:
+               sc->error.code = KNOT_EINVAL;
+               return;
+       }
 
-       sc->error.code = knot_rrset_add_rdata(ctx->rr, sc->r_data, sc->r_data_length, NULL);
-       ctx->rr->ttl = sc->r_ttl;
+       sc->error.code = knot_rrset_add_rdata(to_add, sc->r_data, sc->r_data_length, NULL);
+       to_add->ttl = sc->r_ttl;
 
        if (sc->error.code == KNOT_EOK && sc->buffer_length > 9 && strncmp((const char *)sc->buffer, " end SKR ", 9) == 0) {
                knot_time_t for_time = atol((const char *)sc->buffer + 9);
-               sc->error.code = kasp_db_store_offline_rrsig(*ctx->kctx->kasp_db, for_time, ctx->rr);
-               knot_rdataset_clear(&ctx->rr->rrs, NULL);
+               sc->error.code = kasp_db_store_offline_rrsig(*ctx->kctx->kasp_db, for_time, ctx->rrsig, ctx->dnskey, ctx->cdnskey, ctx->cds);
+               knot_rdataset_clear(&ctx->dnskey->rrs, NULL);
+               knot_rdataset_clear(&ctx->cdnskey->rrs, NULL);
+               knot_rdataset_clear(&ctx->cds->rrs, NULL);
+               knot_rdataset_clear(&ctx->rrsig->rrs, NULL);
        }
 }
 
-static int read_ksr_skr(kdnssec_ctx_t *ctx, const char *infile, void (*cb)(zs_scanner_t *), uint16_t rrtype)
+static int read_ksr_skr(kdnssec_ctx_t *ctx, const char *infile, void (*cb)(zs_scanner_t *))
 {
        zs_scanner_t sc = { 0 };
        int ret = zs_init(&sc, "", KNOT_CLASS_IN, 0);
@@ -352,10 +463,14 @@ static int read_ksr_skr(kdnssec_ctx_t *ctx, const char *infile, void (*cb)(zs_sc
                return KNOT_EFILE;
        }
 
-       knot_rrset_t rr = { 0 };
-       knot_rrset_init(&rr, ctx->zone->dname, rrtype, KNOT_CLASS_IN, ctx->policy->dnskey_ttl);
+       knot_rrset_t dnskey = { 0 }, dnskey_prev = { 0 }, cdnskey = { 0 }, cds = { 0 }, rrsig = { 0 };
+       knot_rrset_init(&dnskey, ctx->zone->dname, KNOT_RRTYPE_DNSKEY, KNOT_CLASS_IN, ctx->policy->dnskey_ttl);
+       knot_rrset_init(&dnskey_prev, ctx->zone->dname, KNOT_RRTYPE_DNSKEY, KNOT_CLASS_IN, ctx->policy->dnskey_ttl);
+       knot_rrset_init(&cdnskey, ctx->zone->dname, KNOT_RRTYPE_CDNSKEY, KNOT_CLASS_IN, 0);
+       knot_rrset_init(&cds, ctx->zone->dname, KNOT_RRTYPE_CDS, KNOT_CLASS_IN, 0);
+       knot_rrset_init(&rrsig, ctx->zone->dname, KNOT_RRTYPE_RRSIG, KNOT_CLASS_IN, ctx->policy->dnskey_ttl);
 
-       ksr_sign_ctx_t pctx = { &rr, ctx };
+       ksr_sign_ctx_t pctx = { &dnskey, &dnskey_prev, &cdnskey, &cds, &rrsig, ctx };
        ret = zs_set_processing(&sc, cb, NULL, &pctx);
        if (ret < 0) {
                zs_deinit(&sc);
@@ -366,17 +481,22 @@ static int read_ksr_skr(kdnssec_ctx_t *ctx, const char *infile, void (*cb)(zs_sc
 
        if (sc.error.code != KNOT_EOK) {
                ret = sc.error.code;
-       } else if (ret < 0 || rr.rrs.count > 0) {
+       } else if (ret < 0 || dnskey.rrs.count > 0 || cdnskey.rrs.count > 0 ||
+                  cds.rrs.count > 0 || rrsig.rrs.count > 0) {
                ret = KNOT_EMALF;
        }
-       knot_rdataset_clear(&rr.rrs, NULL);
+       knot_rdataset_clear(&dnskey.rrs, NULL);
+       knot_rdataset_clear(&dnskey_prev.rrs, NULL);
+       knot_rdataset_clear(&cdnskey.rrs, NULL);
+       knot_rdataset_clear(&cds.rrs, NULL);
+       knot_rdataset_clear(&rrsig.rrs, NULL);
        zs_deinit(&sc);
        return ret;
 }
 
 int keymgr_sign_ksr(kdnssec_ctx_t *ctx, const char *ksr_file)
 {
-       int ret = read_ksr_skr(ctx, ksr_file, ksr_sign_once, KNOT_RRTYPE_DNSKEY);
+       int ret = read_ksr_skr(ctx, ksr_file, ksr_sign_once);
        printf(";; SignedKeyResponse ");
        print_generated_message();
        return ret;
@@ -384,5 +504,5 @@ int keymgr_sign_ksr(kdnssec_ctx_t *ctx, const char *ksr_file)
 
 int keymgr_import_skr(kdnssec_ctx_t *ctx, const char *skr_file)
 {
-       return read_ksr_skr(ctx, skr_file, skr_import_once, KNOT_RRTYPE_RRSIG);
+       return read_ksr_skr(ctx, skr_file, skr_import_once);
 }
diff --git a/tests-extra/tests/dnssec/offline_ksk/test.py b/tests-extra/tests/dnssec/offline_ksk/test.py
deleted file mode 100644 (file)
index 1ac056b..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/env python3
-
-"""
-Test of offline KSK by trying pre-generated ZSK rollover.
-"""
-
-import collections
-import os
-import shutil
-import datetime
-import subprocess
-import time
-from subprocess import check_call
-
-from dnstest.utils import *
-from dnstest.keys import Keymgr
-from dnstest.test import Test
-
-# check zone if keys are present and used for signing
-def check_zone(server, zone, dnskeys, dnskey_rrsigs, soa_rrsigs, msg):
-    qdnskeys = server.dig("example.com", "DNSKEY", bufsize=4096)
-    found_dnskeys = qdnskeys.count("DNSKEY")
-
-    qdnskeyrrsig = server.dig("example.com", "DNSKEY", dnssec=True, bufsize=4096)
-    found_rrsigs = qdnskeyrrsig.count("RRSIG")
-
-    qsoa = server.dig("example.com", "SOA", dnssec=True, bufsize=4096)
-    found_soa_rrsigs = qsoa.count("RRSIG")
-
-    check_log("DNSKEYs: %d (expected %d)" % (found_dnskeys, dnskeys));
-    check_log("RRSIGs: %d (expected %d)" % (found_soa_rrsigs, soa_rrsigs));
-    check_log("DNSKEY-RRSIGs: %d (expected %d)" % (found_rrsigs, dnskey_rrsigs));
-
-    if found_dnskeys != dnskeys:
-        set_err("BAD DNSKEY COUNT: " + msg)
-        detail_log("!DNSKEYs not published and activated as expected: " + msg)
-
-    if found_soa_rrsigs != soa_rrsigs:
-        set_err("BAD RRSIG COUNT: " + msg)
-        detail_log("!RRSIGs not published and activated as expected: " + msg)
-
-    if found_rrsigs != dnskey_rrsigs:
-        set_err("BAD DNSKEY RRSIG COUNT: " + msg)
-        detail_log("!RRSIGs not published and activated as expected: " + msg)
-
-    detail_log(SEP)
-
-    # Valgrind delay breaks the timing!
-    if not server.valgrind:
-        server.zone_backup(zone, flush=True)
-        server.zone_verify(zone)
-
-def wait_for_rrsig_count(t, server, rrtype, rrsig_count, timeout):
-    rtime = 0
-    while True:
-        qdnskeyrrsig = server.dig("example.com", rrtype, dnssec=True, bufsize=4096)
-        found_rrsigs = qdnskeyrrsig.count("RRSIG")
-        if found_rrsigs == rrsig_count:
-            break
-        rtime = rtime + 1
-        t.sleep(1)
-        if rtime > timeout:
-            break
-
-def wait_for_dnskey_count(t, server, dnskey_count, timeout):
-    for rtime in range(1, timeout):
-        qdnskeyrrsig = server.dig("example.com", "DNSKEY", dnssec=True, bufsize=4096)
-        found_dnskeys = qdnskeyrrsig.count("DNSKEY")
-        if found_dnskeys == dnskey_count:
-            break
-        t.sleep(1)
-
-t = Test()
-
-knot = t.server("knot")
-ZONE = "example.com."
-FUTURE = 100
-
-zone = t.zone(ZONE)
-t.link(zone, knot)
-
-knot.zonefile_sync = 24 * 60 * 60
-
-knot.dnssec(zone).enable = True
-knot.dnssec(zone).manual = True
-knot.dnssec(zone).alg = "ECDSAP384SHA384"
-knot.dnssec(zone).dnskey_ttl = 2
-knot.dnssec(zone).zsk_lifetime = 12
-knot.dnssec(zone).ksk_lifetime = 300 # this can be possibly left also infinity
-knot.dnssec(zone).propagation_delay = 3
-knot.port = 1234 # dummy, will be overwritten
-knot.gen_confile()
-
-key_ksk = knot.gen_key(zone, ksk=True, alg="ECDSAP384SHA384", key_len=384)
-key_zsk = knot.gen_key(zone, ksk=False, alg="ECDSAP384SHA384", key_len=384)
-
-Keymgr.run_check(knot.confile, ZONE, "pregenerate", str(FUTURE))
-Keymgr.run_check(knot.confile, ZONE, "presign", str(FUTURE))
-
-os.remove(knot.keydir + "/keys/" + key_ksk.keyid + ".pem")
-
-# parameters
-
-t.start()
-knot.zone_wait(zone)
-check_zone(knot, zone, 2, 1, 1, "init")
-
-wait_for_dnskey_count(t, knot, 3, knot.dnssec(zone).zsk_lifetime)
-check_zone(knot, zone, 3, 1, 1, "ZSK rollover")
-
-t.sleep(2)
-
-wait_for_dnskey_count(t, knot, 2, 2 * (knot.dnssec(zone).propagation_delay + knot.dnssec(zone).dnskey_ttl))
-check_zone(knot, zone, 2, 1, 1, "end")
-
-t.end()
index ac4729e466b32b86c9f00861ee0225a41f0f10e7..33ecef2db1c8fceb197ccd3f0e0fb93ef0a71dc9 100644 (file)
@@ -94,35 +94,23 @@ knot.dnssec(zone).dnskey_ttl = 2
 knot.dnssec(zone).zsk_lifetime = STARTUP + 6*TICK # see ksk1 lifetime
 knot.dnssec(zone).ksk_lifetime = 300 # this can be possibly left also infinity
 knot.dnssec(zone).propagation_delay = TICK-2
-knot.dnssec(zone).cds_publish = "none"
+knot.dnssec(zone).offline_ksk = "on"
 knot.port = 1234 # dummy, will be overwritten
 knot.gen_confile()
 
-def tickf(when):
-    return "+%d" % (STARTUP + when * TICK)
-
-# generate keys, including manual KSK rollover on the beginning
-key_ksk1 = knot.key_gen(ZONE, ksk="true", created="+0", publish="+0", ready="+0", active="+0", retire=tickf(4), remove=tickf(5))
-key_ksk2 = knot.key_gen(ZONE, ksk="true", created="+0", publish=tickf(2), ready=tickf(3), active=tickf(4), retire="+2h", remove="+3h")
-key_zsk1 = knot.key_gen(ZONE, ksk="false", created="+0", publish="+0", active="+0")
-
-# signer knot, copy everything from "knot"
 signer = t.server("knot")
 t.link(zone, signer)
 signer.zones[ZONE].dnssec = knot.zones[ZONE].dnssec
 signer.port = 1235
 signer.gen_confile()
-_, keys_list, _ = Keymgr.run_check(knot.confile, ZONE, "list")
-for keyparm in keys_list.splitlines():
-    pem = knot.keydir + "/keys/" + keyparm.split()[0] + ".pem"
-    parm1 = keyparm.split()[1]
-    parm2 = keyparm.replace("-", "_").split()[7:]
-    Keymgr.run_check(signer.confile, ZONE, "import-pem", pem, parm1, *parm2)
-
-# delete KSKs in "knot" and ZSKs in "signer"
-os.remove(knot.keydir + "/keys/" + key_ksk1 + ".pem")
-os.remove(knot.keydir + "/keys/" + key_ksk2 + ".pem")
-os.remove(signer.keydir + "/keys/" + key_zsk1 + ".pem")
+
+def tickf(when):
+    return "+%d" % (STARTUP + when * TICK)
+
+# generate keys, including manual KSK rollover on the beginning
+key_ksk1 = signer.key_gen(ZONE, ksk="true", created="+0", publish="+0", ready="+0", active="+0", retire=tickf(4), remove=tickf(5))
+key_ksk2 = signer.key_gen(ZONE, ksk="true", created="+0", publish=tickf(2), ready=tickf(3), active=tickf(4), retire="+2h", remove="+3h")
+key_zsk1 = knot.key_gen(ZONE, ksk="false", created="+0", publish="+0", active="+0")
 
 # pregenerate keys, exchange KSR, pre-sign it, exchange SKR
 KSR = knot.keydir + "/ksr"
index c6377dc09b2a0a4530f0bbfb1ddcb34a0a81b87a..4958ad47a46245117980373e9a77ae47608148ed 100644 (file)
@@ -58,6 +58,7 @@ class ZoneDnssec(object):
         self.ksk_sbm_check_interval = None
         self.ksk_shared = None
         self.cds_publish = None
+        self.offline_ksk = None
 
 class Zone(object):
     '''DNS zone description'''
@@ -1199,6 +1200,7 @@ class Knot(Server):
                 s.item("ksk-submission", z.name)
             self._bool(s, "ksk-shared", z.dnssec.ksk_shared)
             self._str(s, "cds-cdnskey-publish", z.dnssec.cds_publish)
+            self._str(s, "offline-ksk", z.dnssec.offline_ksk)
         if have_policy:
             s.end()