diff --git a/src/libknot/zone/sign.c b/src/libknot/zone/sign.c index 68075dbb35fa95652d10f9c724b383903ce309eb..be1634545f39beaf8e94501fdcf0403cbe9acc4a 100644 --- a/src/libknot/zone/sign.c +++ b/src/libknot/zone/sign.c @@ -43,10 +43,12 @@ typedef struct { bool is_ksk[MAX_ZONE_KEYS]; } knot_zone_keys_t; -static knot_rrset_t *create_rrsig_rrset(knot_dname_t *owner, - const knot_rrset_t *cover) +static knot_rrset_t *create_rrsig_rrset(const knot_rrset_t *cover) { - return knot_rrset_new(owner, KNOT_RRTYPE_RRSIG, cover->rclass, cover->ttl); + return knot_rrset_new(cover->owner, + KNOT_RRTYPE_RRSIG, + cover->rclass, + cover->ttl); } // COPIED FROM SIG(0) AND MODIFIED @@ -118,20 +120,19 @@ static uint8_t *create_rrsig_rdata(knot_rrset_t *rrsig, knot_dnssec_key_t *key) return knot_rrset_create_rdata(rrsig, rdata_size); } -static int sign_rrset_one(knot_rrset_t *rrsig, - const knot_dname_t *owner, +static int sign_rrset_one(knot_rrset_t *rrsigs, const knot_rrset_t *covered, knot_dnssec_key_t *key, knot_dnssec_sign_context_t *sign_ctx) { - uint8_t *rdata = create_rrsig_rdata(rrsig, key); + uint8_t *rdata = create_rrsig_rdata(rrsigs, key); assert(rdata); // move to caller function, derive from key validity uint32_t sig_incept = (uint32_t)time(NULL); uint32_t sig_expire = sig_incept + 2592000; - rrsig_write_rdata(rdata, key, owner, covered, sig_incept, sig_expire); + rrsig_write_rdata(rdata, key, covered->owner, covered, sig_incept, sig_expire); // RFC 4034 // The signature coveres RRSIG RDATA field (excluding the signature) @@ -179,63 +180,109 @@ static int sign_rrset_one(knot_rrset_t *rrsig, return KNOT_EOK; } -static int sign_rrset(knot_dname_t *owner, const knot_rrset_t *covered, - knot_zone_keys_t *zone_keys, knot_rrset_t **out_rrsig) +static bool signature_exists(const knot_rrset_t *rrsigs, + const knot_dnssec_key_t *key) { - assert(owner); - assert(covered); - assert(zone_keys); - assert(out_rrsig); + for (int i = 0; i < rrsigs->rdata_count; i++) { + uint16_t keytag = knot_rrset_rdata_rrsig_key_tag(rrsigs, i); + if (keytag == key->keytag) + return true; + } - char typestr[10] = ""; - knot_rrtype_to_string(covered->type, typestr, 10); - fprintf(stderr, "signing rrset %s (%s)\n", knot_dname_to_str(owner), typestr); + return false; +} - knot_rrset_t *rrsig = create_rrsig_rrset(owner, covered); - assert(rrsig); +static int add_missing_signatures(const knot_rrset_t *covered, + knot_rrset_t *rrsigs, + knot_zone_keys_t *zone_keys) +{ + assert(covered); + assert(rrsigs); + assert(zone_keys); bool use_ksk = covered->type == KNOT_RRTYPE_DNSKEY; for (int i = 0; i < zone_keys->count; i++) { - if (zone_keys->is_ksk[i] && !use_ksk) + if (use_ksk != zone_keys->is_ksk[i]) continue; knot_dnssec_key_t *key = &zone_keys->keys[i]; knot_dnssec_sign_context_t *ctx = zone_keys->contexts[i]; - fprintf(stderr, "signing with key %d (%s)\n", key->keytag, zone_keys->is_ksk[i] ? "KSK" : "ZSK"); + if (signature_exists(rrsigs, key)) { + fprintf(stderr, "[key %d] sig exists\n", key->keytag); + continue; + } + + fprintf(stderr, "[key %d] signing with %s\n", key->keytag, zone_keys->is_ksk[i] ? "KSK" : "ZSK"); - int r = sign_rrset_one(rrsig, owner, covered, key, ctx); + int r = sign_rrset_one(rrsigs, covered, key, ctx); if (r != KNOT_EOK) { fprintf(stderr, "sign_rrset_one() failed %d\n", r); return r; } } - *out_rrsig = rrsig; - return KNOT_EOK; } +static int copy_valid_signatures(knot_rrset_t *from, knot_rrset_t *to) +{ + assert(from); + assert(to); + + int result = KNOT_EOK; + uint32_t now = (uint32_t)time(NULL); + uint32_t expiration; + + for (int i = 0; i < from->rdata_count; i++) { + expiration = knot_rrset_rdata_rrsig_sig_expiration(from, i); + if (expiration < now || expiration - now < 7200) { + fprintf(stderr, "removing expired signature %d %d\n", expiration, now); + continue; + } + + fprintf(stderr, "keeping signature\n"); + result = knot_rrset_add_rr_from_rrset(to, from, i); + if (result != KNOT_EOK) + break; + } + + return result; +} + static int sign_node(const knot_node_t *node, knot_zone_keys_t *zone_keys) { assert(node); for (int i = 0; i < node->rrset_count; i++) { knot_rrset_t *rrset = node->rrset_tree[i]; - knot_rrset_t *sig_rrset = NULL; + knot_rrset_t *rrsigs = rrset->rrsigs; + knot_rrset_t *new_rrsigs; - int r = sign_rrset(node->owner, rrset, zone_keys, &sig_rrset); - if (r != KNOT_EOK) { - fprintf(stderr, "sign_rrset() failed\n"); - return r; + new_rrsigs = create_rrsig_rrset(rrset); + if (!new_rrsigs) + return KNOT_ENOMEM; + + assert(knot_dname_compare(rrsigs->owner, new_rrsigs->owner) == 0); + assert(rrsigs->type == new_rrsigs->type); + assert(rrsigs->rclass == new_rrsigs->rclass); + assert(rrsigs->ttl == new_rrsigs->ttl); + + int result = copy_valid_signatures(rrsigs, new_rrsigs); + if (result != KNOT_EOK) { + knot_rrset_free(&new_rrsigs); + return result; } - if (!sig_rrset) { - fprintf(stderr, "got empty RRSIG\n"); - continue; + + result = add_missing_signatures(rrset, new_rrsigs, zone_keys); + if (result != KNOT_EOK) { + fprintf(stderr, "sign_rrset() failed\n"); + return result; } - knot_rrset_add_rrsigs(rrset, sig_rrset, KNOT_RRSET_DUPL_REPLACE); + knot_rrset_free(&rrsigs); + rrset->rrsigs = new_rrsigs; } return KNOT_EOK;