Skip to content
Snippets Groups Projects
Commit 1c6e101e authored by Jan Včelák's avatar Jan Včelák :rocket:
Browse files

server: clean NSEC3PARAM replacement

parent 56ede3d5
No related branches found
No related tags found
1 merge request!547NSEC3 resalt
......@@ -195,161 +195,198 @@ knot_dname_t *knot_create_nsec3_owner(const knot_dname_t *owner,
return result;
}
static int set_nsec3param(knot_rrset_t *rrset, const kdnssec_ctx_t *dnssec_ctx)
static bool nsec3param_valid(const knot_rdataset_t *rrs,
const dnssec_nsec3_params_t *params)
{
assert(rrset);
assert(dnssec_ctx);
assert(rrs);
assert(params);
// NSEC3 disabled
if (params->algorithm == 0) {
return false;
}
// multiple NSEC3 records
if (rrs->rr_count != 1) {
return false;
}
knot_rdata_t *rrd = knot_rdataset_at(rrs, 0);
dnssec_binary_t rdata = {
.size = knot_rdata_rdlen(rrd),
.data = knot_rdata_data(rrd),
};
dnssec_nsec3_params_t parsed = { 0 };
int r = dnssec_nsec3_params_from_rdata(&parsed, &rdata);
if (r != DNSSEC_EOK) {
return false;
}
bool equal = parsed.algorithm == params->algorithm &&
parsed.flags == params->flags &&
parsed.iterations == params->iterations &&
dnssec_binary_cmp(&parsed.salt, &params->salt) == 0;
dnssec_nsec3_params_free(&parsed);
return equal;
}
dnssec_nsec3_params_t *new_params = &dnssec_ctx->policy->nsec3_params;
dnssec_binary_t *new_salt = dnssec_ctx->zone->nsec3_salt;
static int remove_nsec3param(const zone_contents_t *zone, changeset_t *changeset)
{
assert(zone);
assert(changeset);
knot_rrset_t rrset = node_rrset(zone->apex, KNOT_RRTYPE_NSEC3PARAM);
int ret = changeset_rem_rrset(changeset, &rrset, 0);
if (ret != KNOT_EOK) {
return ret;
}
rrset = node_rrset(zone->apex, KNOT_RRTYPE_RRSIG);
if (!knot_rrset_empty(&rrset)) {
knot_rrset_t rrsig;
knot_rrset_init(&rrsig, zone->apex->owner, KNOT_RRTYPE_RRSIG, KNOT_CLASS_IN);
ret = knot_synth_rrsig(KNOT_RRTYPE_NSEC3PARAM, &rrset.rrs, &rrsig.rrs, NULL);
if (ret != KNOT_EOK) {
return ret;
}
ret = changeset_rem_rrset(changeset, &rrsig, 0);
knot_rdataset_clear(&rrsig.rrs, NULL);
if (ret != KNOT_EOK) {
return ret;
}
}
return KNOT_EOK;
}
static int set_nsec3param(knot_rrset_t *rrset, const dnssec_nsec3_params_t *params)
{
assert(rrset);
assert(params);
// Prepare wire rdata.
size_t rdata_len = 3 * sizeof(uint8_t) + sizeof(uint16_t) + new_salt->size;
size_t rdata_len = 3 * sizeof(uint8_t) + sizeof(uint16_t) + params->salt.size;
uint8_t rdata[rdata_len];
wire_ctx_t wire = wire_ctx_init(rdata, rdata_len);
wire_ctx_write_u8(&wire, new_params->algorithm);
wire_ctx_write_u8(&wire, new_params->flags);
wire_ctx_write_u16(&wire, new_params->iterations);
wire_ctx_write_u8(&wire, new_salt->size);
wire_ctx_write(&wire, new_salt->data, new_salt->size);
wire_ctx_write_u8(&wire, params->algorithm);
wire_ctx_write_u8(&wire, params->flags);
wire_ctx_write_u16(&wire, params->iterations);
wire_ctx_write_u8(&wire, params->salt.size);
wire_ctx_write(&wire, params->salt.data, params->salt.size);
if (wire.error != KNOT_EOK) {
return wire.error;
}
assert(wire_ctx_available(&wire) == 0);
return knot_rrset_add_rdata(rrset, rdata, rdata_len, 0, NULL);
}
static bool match_nsec3param(const knot_nsec3_params_t *params,
const kdnssec_ctx_t *dnssec_ctx)
static int add_nsec3param(const zone_contents_t *zone, changeset_t *changeset,
const dnssec_nsec3_params_t *params)
{
assert(zone);
assert(changeset);
assert(params);
assert(dnssec_ctx);
dnssec_nsec3_params_t *new_params = &dnssec_ctx->policy->nsec3_params;
dnssec_binary_t *new_salt = dnssec_ctx->zone->nsec3_salt;
knot_rrset_t *rrset = NULL;
rrset = knot_rrset_new(zone->apex->owner, KNOT_RRTYPE_NSEC3PARAM, KNOT_CLASS_IN, NULL);
if (!rrset) {
return KNOT_ENOMEM;
}
return params->algorithm == new_params->algorithm &&
params->flags == new_params->flags &&
params->iterations == new_params->iterations &&
params->salt_length == new_salt->size &&
memcmp(params->salt, new_salt->data, new_salt->size) == 0;
int r = set_nsec3param(rrset, params);
if (r != KNOT_EOK) {
knot_rrset_free(&rrset, NULL);
return r;
}
r = changeset_add_rrset(changeset, rrset, 0);
knot_rrset_free(&rrset, NULL);
return r;
}
static int update_nsec3param(const zone_contents_t *zone,
const kdnssec_ctx_t *dnssec_ctx,
changeset_t *changeset)
changeset_t *changeset,
const dnssec_nsec3_params_t *params)
{
assert(zone);
assert(dnssec_ctx);
assert(changeset);
assert(params);
dnssec_kasp_policy_t *policy = dnssec_ctx->policy;
knot_rdataset_t *nsec3param = node_rdataset(zone->apex, KNOT_RRTYPE_NSEC3PARAM);
bool valid = nsec3param && nsec3param_valid(nsec3param, params);
// Check for changed NSEC3PARAM record.
bool changed = false;
if (nsec3param != NULL && policy->nsec3_enabled &&
match_nsec3param(&zone->nsec3_params, dnssec_ctx)) {
changed = true;
}
// Remove redundant or changed NSEC3PARAM record and its RRSIG.
if ((nsec3param != NULL && !policy->nsec3_enabled) || changed) {
knot_rrset_t rrset = node_rrset(zone->apex, KNOT_RRTYPE_NSEC3PARAM);
int ret = changeset_rem_rrset(changeset, &rrset, 0);
if (ret != KNOT_EOK) {
return ret;
if (nsec3param && !valid) {
int r = remove_nsec3param(zone, changeset);
if (r != KNOT_EOK) {
return r;
}
}
rrset = node_rrset(zone->apex, KNOT_RRTYPE_RRSIG);
if (!knot_rrset_empty(&rrset)) {
knot_rrset_t synth_rrsig;
knot_rrset_init(&synth_rrsig, zone->apex->owner,
KNOT_RRTYPE_RRSIG, KNOT_CLASS_IN);
ret = knot_synth_rrsig(KNOT_RRTYPE_NSEC3PARAM, &rrset.rrs,
&synth_rrsig.rrs, NULL);
if (ret != KNOT_EOK) {
return ret;
}
ret = changeset_rem_rrset(changeset, &synth_rrsig, 0);
knot_rdataset_clear(&synth_rrsig.rrs, NULL);
if (ret != KNOT_EOK) {
return ret;
}
}
if (params->algorithm != 0 && !valid) {
return add_nsec3param(zone, changeset, params);
}
// Also remove the record from the zone.
knot_rdataset_clear(nsec3param, NULL);
node_remove_rdataset(zone->apex, KNOT_RRTYPE_NSEC3PARAM);
return KNOT_EOK;
}
// Reset zone nsec3 paramaters.
knot_nsec3param_free((knot_nsec3_params_t *)&zone->nsec3_params);
memset((knot_nsec3_params_t *)&zone->nsec3_params, 0,
sizeof(knot_nsec3_params_t));
static uint32_t soa_minimum(const zone_contents_t *zone)
{
const knot_rdataset_t *soa = node_rdataset(zone->apex, KNOT_RRTYPE_SOA);
if (soa == NULL) {
return 0;
}
// Add new NSEC3PARAM record.
if ((nsec3param == NULL && policy->nsec3_enabled) || changed) {
knot_rrset_t *rrset = knot_rrset_new(zone->apex->owner,
KNOT_RRTYPE_NSEC3PARAM,
KNOT_CLASS_IN, NULL);
if (rrset == NULL) {
return KNOT_ENOMEM;
}
int ret = set_nsec3param(rrset, dnssec_ctx);
if (ret != KNOT_EOK) {
knot_rrset_free(&rrset, NULL);
return ret;
}
return knot_soa_minimum(soa);
}
ret = changeset_add_rrset(changeset, rrset, 0);
if (ret != KNOT_EOK) {
knot_rrset_free(&rrset, NULL);
return ret;
}
/*!
* \brief Initialize NSEC3PARAM based on the signing policy.
*
* \note For NSEC, the algorithm number is set to 0.
*/
static dnssec_nsec3_params_t nsec3param_init(const dnssec_kasp_policy_t *policy,
const dnssec_kasp_zone_t *zone)
{
assert(policy);
assert(zone);
// Update zone nsec3 paramaters.
ret = knot_nsec3param_from_wire((knot_nsec3_params_t *)&zone->nsec3_params,
&rrset->rrs);
knot_rrset_free(&rrset, NULL);
if (ret != KNOT_EOK) {
return ret;
}
dnssec_nsec3_params_t params = { 0 };
if (policy->nsec3_enabled) {
params.algorithm = DNSSEC_NSEC3_ALGORITHM_SHA1;
params.iterations = policy->nsec3_iterations;
params.salt = zone->nsec3_salt;
}
return KNOT_EOK;
return params;
}
int knot_zone_create_nsec_chain(const zone_contents_t *zone,
changeset_t *changeset,
const zone_keyset_t *zone_keys,
const kdnssec_ctx_t *dnssec_ctx)
const kdnssec_ctx_t *ctx)
{
if (zone == NULL || changeset == NULL || dnssec_ctx == NULL) {
if (zone == NULL || changeset == NULL || ctx == NULL) {
return KNOT_EINVAL;
}
const knot_rdataset_t *soa = node_rdataset(zone->apex, KNOT_RRTYPE_SOA);
if (soa == NULL) {
return KNOT_EINVAL;
}
uint32_t nsec_ttl = knot_soa_minimum(soa);
uint32_t nsec_ttl = soa_minimum(zone);
dnssec_nsec3_params_t params = nsec3param_init(ctx->policy, ctx->zone);
// Update NSEC3PARAM record.
if (!dnssec_ctx->legacy) {
int ret = update_nsec3param(zone, dnssec_ctx, changeset);
if (ret != KNOT_EOK) {
return ret;
}
int ret = update_nsec3param(zone, changeset, &params);
if (ret != KNOT_EOK) {
return ret;
}
if (dnssec_ctx->policy->nsec3_enabled) {
int ret = knot_nsec3_create_chain(zone, nsec_ttl, changeset);
if (ctx->policy->nsec3_enabled) {
int ret = knot_nsec3_create_chain(zone, &params, nsec_ttl, changeset);
if (ret != KNOT_EOK) {
return ret;
}
......@@ -372,5 +409,5 @@ int knot_zone_create_nsec_chain(const zone_contents_t *zone,
}
// Sign newly created records right away.
return knot_zone_sign_nsecs_in_changeset(zone_keys, dnssec_ctx, changeset);
return knot_zone_sign_nsecs_in_changeset(zone_keys, ctx, changeset);
}
......@@ -35,6 +35,7 @@ int event_flush(conf_t *conf, zone_t *zone);
int event_notify(conf_t *conf, zone_t *zone);
/*! \brief Signs the zone using its DNSSEC keys. */
int event_dnssec(conf_t *conf, zone_t *zone);
void schedule_dnssec(zone_t *zone, time_t refresh_at);
/*! \brief Get next bootstrap interval. */
uint32_t bootstrap_next(uint32_t interval);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment