zone-keys.c 12.9 KB
Newer Older
1
/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <assert.h>
18
#include <limits.h>
19

20
#include "dnssec/error.h"
21
#include "knot/common/log.h"
22
#include "knot/dnssec/zone-keys.h"
23
#include "libknot/libknot.h"
24

25 26
#define MAX_KEY_INFO 128

27
dynarray_define(keyptr, zone_key_t *, DYNARRAY_VISIBILITY_PUBLIC)
28

29 30 31 32 33 34 35 36
const uint16_t DNSKEY_FLAGS_KSK = 257;
const uint16_t DNSKEY_FLAGS_ZSK = 256;

uint16_t dnskey_flags(bool is_ksk)
{
	return is_ksk ? DNSKEY_FLAGS_KSK : DNSKEY_FLAGS_ZSK;
}

37
int kdnssec_generate_key(kdnssec_ctx_t *ctx, bool ksk, bool zsk, knot_kasp_key_t **key_ptr)
38 39 40 41 42
{
	assert(ctx);
	assert(ctx->zone);
	assert(ctx->keystore);
	assert(ctx->policy);
43
	assert(ksk || zsk);
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81

	dnssec_key_algorithm_t algorithm = ctx->policy->algorithm;
	unsigned size = ksk ? ctx->policy->ksk_size : ctx->policy->zsk_size;

	// generate key in the keystore

	char *id = NULL;
	int r = dnssec_keystore_generate_key(ctx->keystore, algorithm, size, &id);
	if (r != KNOT_EOK) {
		return r;
	}

	// create KASP key

	dnssec_key_t *dnskey = NULL;
	r = dnssec_key_new(&dnskey);
	if (r != KNOT_EOK) {
		free(id);
		return r;
	}

	r = dnssec_key_set_dname(dnskey, ctx->zone->dname);
	if (r != KNOT_EOK) {
		dnssec_key_free(dnskey);
		free(id);
		return r;
	}

	dnssec_key_set_flags(dnskey, dnskey_flags(ksk));
	dnssec_key_set_algorithm(dnskey, algorithm);

	r = dnssec_key_import_keystore(dnskey, ctx->keystore, id);
	if (r != KNOT_EOK) {
		dnssec_key_free(dnskey);
		free(id);
		return r;
	}

82
	knot_kasp_key_t *key = calloc(1, sizeof(*key));
83 84 85 86 87 88 89 90
	if (!key) {
		dnssec_key_free(dnskey);
		free(id);
		return KNOT_ENOMEM;
	}

	key->id = id;
	key->key = dnskey;
91 92
	key->is_ksk = ksk;
	key->is_zsk = zsk;
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
	key->timing.created = ctx->now;

	r = kasp_zone_append(ctx->zone, key);
	free(key);
	if (r != KNOT_EOK) {
		dnssec_key_free(dnskey);
		free(id);
		return r;
	}

	if (key_ptr) {
		*key_ptr = &ctx->zone->keys[ctx->zone->num_keys - 1];
	}

	return KNOT_EOK;
}

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
int kdnssec_share_key(kdnssec_ctx_t *ctx, const knot_dname_t *from_zone, const char *key_id)
{
	knot_dname_t *to_zone = knot_dname_copy(ctx->zone->dname, NULL);
	if (to_zone == NULL) {
		return KNOT_ENOMEM;
	}

	int ret = kdnssec_ctx_commit(ctx);
	if (ret != KNOT_EOK) {
		free(to_zone);
		return ret;
	}

	ret = kasp_db_share_key(*ctx->kasp_db, from_zone, ctx->zone->dname, key_id);
	if (ret != KNOT_EOK) {
		free(to_zone);
		return ret;
	}

	kasp_zone_clear(ctx->zone);
	ret = kasp_zone_load(ctx->zone, to_zone, *ctx->kasp_db);
	free(to_zone);
	return ret;
}

135
int kdnssec_delete_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *key_ptr)
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
{
	assert(ctx);
	assert(ctx->zone);
	assert(ctx->keystore);
	assert(ctx->policy);

	ssize_t key_index = key_ptr - ctx->zone->keys;

	if (key_index < 0 || key_index >= ctx->zone->num_keys) {
		return KNOT_EINVAL;
	}

	bool key_still_used_in_keystore = false;
	int ret = kasp_db_delete_key(*ctx->kasp_db, ctx->zone->dname, key_ptr->id, &key_still_used_in_keystore);
	if (ret != KNOT_EOK) {
		return ret;
	}

154
	if (!key_still_used_in_keystore && !key_ptr->is_pub_only) {
155 156 157 158 159 160 161 162 163 164 165 166 167
		ret = dnssec_keystore_remove_key(ctx->keystore, key_ptr->id);
		if (ret != KNOT_EOK) {
			return ret;
		}
	}

	dnssec_key_free(key_ptr->key);
	free(key_ptr->id);
	memmove(key_ptr, key_ptr + 1, (ctx->zone->num_keys - key_index - 1) * sizeof(*key_ptr));
	ctx->zone->num_keys--;
	return KNOT_EOK;
}

168
/*!
169
 * \brief Get key feature flags from key parameters.
170
 */
171
static int set_key(knot_kasp_key_t *kasp_key, knot_time_t now, zone_key_t *zone_key)
172
{
173 174 175
	assert(kasp_key);
	assert(zone_key);

176
	knot_kasp_key_timing_t *timing = &kasp_key->timing;
177

178
	// cryptographic context
179

180 181 182
	dnssec_sign_ctx_t *ctx = NULL;
	int r = dnssec_sign_new(&ctx, kasp_key->key);
	if (r != DNSSEC_EOK) {
183
		return r;
184 185
	}

186
	zone_key->id = kasp_key->id;
187 188
	zone_key->key = kasp_key->key;
	zone_key->ctx = ctx;
189

190
	// next event computation
191

192
	knot_time_t next = 0;
193 194 195
	knot_time_t timestamps[] = {
		timing->pre_active,
		timing->publish,
196
		timing->ready,
197 198 199 200 201
		timing->active,
		timing->retire_active,
		timing->retire,
		timing->post_active,
		timing->remove,
202 203
	};

204
	for (int i = 0; i < sizeof(timestamps) / sizeof(knot_time_t); i++) {
205 206
		knot_time_t ts = timestamps[i];
		if (knot_time_cmp(now, ts) < 0 && knot_time_cmp(ts, next) < 0) {
207
			next = ts;
208 209 210
		}
	}

211 212
	zone_key->next_event = next;

213 214
	zone_key->is_ksk = kasp_key->is_ksk;
	zone_key->is_zsk = kasp_key->is_zsk;
215

216
	zone_key->is_public = (knot_time_cmp(timing->publish, now) <= 0 &&
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
	                       knot_time_cmp(timing->post_active, now) > 0 &&
	                       knot_time_cmp(timing->remove, now) > 0);

	zone_key->is_active = (((zone_key->is_zsk && knot_time_cmp(timing->pre_active, now) <= 0) ||
	                        (knot_time_cmp(timing->pre_active, now) <= 0 && knot_time_cmp(timing->publish, now) <= 0) ||
	                        knot_time_cmp(timing->ready, now) <= 0 ||
	                        knot_time_cmp(timing->active, now) <= 0) &&
	                       knot_time_cmp(timing->retire, now) > 0 &&
	                       (zone_key->is_zsk || knot_time_cmp(timing->post_active, now) > 0) &&
	                       knot_time_cmp(timing->remove, now) > 0);

	zone_key->cds_priority = (knot_time_cmp(timing->ready, now) <= 0 ? (
	                          (knot_time_cmp(timing->active, now) <= 0) ? (
	                           (knot_time_cmp(timing->retire_active, now) <= 0 ||
	                            knot_time_cmp(timing->retire, now) <= 0) ? 0 : 1) : 2) : 0);
232

233
	return KNOT_EOK;
234 235
}

236 237 238 239 240 241 242 243 244 245 246 247 248
/*!
 * \brief Check if algorithm is allowed with NSEC3.
 */
static bool is_nsec3_allowed(uint8_t algorithm)
{
	switch (algorithm) {
	case DNSSEC_KEY_ALGORITHM_RSA_SHA1:
		return false;
	default:
		return true;
	}
}

249
static void ksk2csk(kdnssec_ctx_t *ctx, zone_keyset_t *keyset, uint8_t alg)
250
{
251 252 253 254 255 256 257
	for (size_t j = 0; j < keyset->count; j++) {
		zone_key_t *key = &keyset->keys[j];
		if (dnssec_key_get_algorithm(key->key) == alg) {
			assert(key->is_ksk);
			key->is_zsk = true;
		}
	}
258

259 260 261 262 263 264 265
	for (size_t i = 0; i < ctx->zone->num_keys; i++) {
		knot_kasp_key_t *key = &ctx->zone->keys[i];
		if (dnssec_key_get_algorithm(key->key) == alg) {
			assert(key->is_ksk);
			key->is_zsk = true;
		}
	}
266

267 268 269 270 271 272 273 274
	log_zone_info(ctx->zone->dname, "DNSSEC, Single-Type Signing "
	                                "Scheme enabled");
}

static int walk_algorithms(kdnssec_ctx_t *ctx, zone_keyset_t *keyset)
{
	uint8_t alg_usage[256] = { 0 };
	bool keys_changed = false, have_active_alg = false;
275

276 277
	for (size_t i = 0; i < keyset->count; i++) {
		zone_key_t *key = &keyset->keys[i];
278
		uint8_t alg = dnssec_key_get_algorithm(key->key);
279

280 281 282 283
		if (ctx->policy->nsec3_enabled && !is_nsec3_allowed(alg)) {
			log_zone_warning(ctx->zone->dname, "DNSSEC, key %d "
			                 "cannot be used with NSEC3",
			                 dnssec_key_get_keytag(key->key));
284 285
			key->is_public = false;
			key->is_active = false;
286
			key->cds_priority = 0;
287 288 289
			continue;
		}

290 291 292 293
		if (key->is_ksk && key->is_public) { alg_usage[alg] |= 1; }
		if (key->is_zsk && key->is_public) { alg_usage[alg] |= 2; }
		if (key->is_ksk && key->is_active) { alg_usage[alg] |= 4; }
		if (key->is_zsk && key->is_active) { alg_usage[alg] |= 8; }
294 295
	}

296 297 298
	for (size_t i = 0; i < sizeof(alg_usage); i++) {
		if (!(alg_usage[i] & 3)) {
			continue; // no public keys, ignore
299
		}
300 301 302 303 304 305 306 307 308 309 310
		switch (alg_usage[i]) {
		case 5: // because migrating from older version OR from manual setup
			ksk2csk(ctx, keyset, i);
			alg_usage[i] |= 10;
			keys_changed = true;
			// FALLTHROUGH
		case 15: // all keys ready for signing
			have_active_alg = true;
			break;
		default:
			return KNOT_DNSSEC_EMISSINGKEYTYPE;
311 312 313
		}
	}

314 315
	if (!have_active_alg) {
		return KNOT_DNSSEC_ENOKEY;
316 317
	}

318 319
	if (keys_changed) {
		return kdnssec_ctx_commit(ctx);
320 321 322 323 324
	}

	return KNOT_EOK;
}

325 326 327
/*!
 * \brief Load private keys for active keys.
 */
328
static int load_private_keys(dnssec_keystore_t *keystore, zone_keyset_t *keyset)
329
{
330
	assert(keystore);
331
	assert(keyset);
332

333
	for (size_t i = 0; i < keyset->count; i++) {
334
		if (!keyset->keys[i].is_active) {
335 336
			continue;
		}
337

338 339
		zone_key_t *key = &keyset->keys[i];
		int r = dnssec_key_import_keystore(key->key, keystore, key->id);
340
		if (r != DNSSEC_EOK && r != DNSSEC_KEY_ALREADY_PRESENT) {
341
			return r;
342
		}
343 344
	}

345
	return DNSSEC_EOK;
346 347
}

348
/*!
349
 * \brief Log information about zone keys.
350
 */
351
static void log_key_info(const zone_key_t *key, char *out, size_t out_len)
352
{
353
	assert(key);
354
	assert(out);
355

356 357 358 359 360 361 362 363 364 365
	uint8_t alg_code = dnssec_key_get_algorithm(key->key);
	const knot_lookup_t *alg = knot_lookup_by_id(knot_dnssec_alg_names, alg_code);

	char alg_code_str[8] = "";
	if (alg == NULL) {
		(void)snprintf(alg_code_str, sizeof(alg_code_str), "%d", alg_code);
	}

	(void)snprintf(out, out_len, "DNSSEC, key, tag %5d, algorithm %s%s%s%s%s",
	               dnssec_key_get_keytag(key->key),
366 367 368 369 370
	               (alg != NULL                ? alg->name  : alg_code_str),
	               (key->is_ksk ? (key->is_zsk ? ", CSK" : ", KSK") : ""),
	               (key->is_public             ? ", public" : ""),
	               (key->cds_priority > 1      ? ", ready"  : ""),
	               (key->is_active             ? ", active" : ""));
371 372 373 374 375 376 377 378 379
}

int log_key_sort(const void *a, const void *b)
{
	const char *alg_a = strstr(a, "alg");
	const char *alg_b = strstr(b, "alg");
	assert(alg_a != NULL && alg_b != NULL);

	return strcmp(alg_a, alg_b);
380
}
381

382
/*!
383
 * \brief Load zone keys and init cryptographic context.
384
 */
385
int load_zone_keys(kdnssec_ctx_t *ctx, zone_keyset_t *keyset_ptr, bool verbose)
386
{
387
	if (!ctx || !keyset_ptr) {
388 389
		return KNOT_EINVAL;
	}
390

391
	zone_keyset_t keyset = { 0 };
392

393 394
	if (ctx->zone->num_keys < 1) {
		log_zone_error(ctx->zone->dname, "DNSSEC, no keys are available");
395
		return KNOT_DNSSEC_ENOKEY;
396 397
	}

398
	keyset.count = ctx->zone->num_keys;
399
	keyset.keys = calloc(keyset.count, sizeof(zone_key_t));
400 401 402 403
	if (!keyset.keys) {
		free_zone_keys(&keyset);
		return KNOT_ENOMEM;
	}
404

405 406 407 408
	char key_info[ctx->zone->num_keys][MAX_KEY_INFO];
	for (size_t i = 0; i < ctx->zone->num_keys; i++) {
		knot_kasp_key_t *kasp_key = &ctx->zone->keys[i];
		set_key(kasp_key, ctx->now, &keyset.keys[i]);
409 410 411 412 413 414 415
		if (verbose) {
			log_key_info(&keyset.keys[i], key_info[i], MAX_KEY_INFO);
		}
	}

	// Sort the keys by algorithm name.
	if (verbose) {
416 417 418
		qsort(key_info, ctx->zone->num_keys, MAX_KEY_INFO, log_key_sort);
		for (size_t i = 0; i < ctx->zone->num_keys; i++) {
			log_zone_info(ctx->zone->dname, "%s", key_info[i]);
419
		}
420 421
	}

422 423 424 425
	int ret = walk_algorithms(ctx, &keyset);
	if (ret != KNOT_EOK) {
		log_zone_error(ctx->zone->dname, "DNSSEC, keys validation failed (%s)",
		               knot_strerror(ret));
426
		free_zone_keys(&keyset);
427
		return ret;
428 429
	}

430 431 432 433 434
	ret = load_private_keys(ctx->keystore, &keyset);
	ret = knot_error_from_libdnssec(ret);
	if (ret != KNOT_EOK) {
		log_zone_error(ctx->zone->dname, "DNSSEC, failed to load private "
		               "keys (%s)", knot_strerror(ret));
435
		free_zone_keys(&keyset);
436
		return ret;
437 438
	}

439 440
	*keyset_ptr = keyset;

441
	return KNOT_EOK;
442 443
}

444 445 446
/*!
 * \brief Free structure with zone keys and associated DNSSEC contexts.
 */
447
void free_zone_keys(zone_keyset_t *keyset)
448
{
449
	if (!keyset) {
450 451 452
		return;
	}

453 454
	for (size_t i = 0; i < keyset->count; i++) {
		dnssec_sign_free(keyset->keys[i].ctx);
455
		dnssec_binary_free(&keyset->keys[i].precomputed_ds);
456
	}
457

458 459 460
	free(keyset->keys);

	memset(keyset, '\0', sizeof(*keyset));
461
}
462

463
/*!
464
 * \brief Get zone keys by keytag.
465
 */
466
struct keyptr_dynarray get_zone_keys(const zone_keyset_t *keyset, uint16_t search)
467
{
468
	struct keyptr_dynarray res = { 0 };
469

470
	for (size_t i = 0; keyset && i < keyset->count; i++) {
471
		zone_key_t *key = &keyset->keys[i];
472 473
		if (key != NULL && dnssec_key_get_keytag(key->key) == search) {
			keyptr_dynarray_add(&res, &key);
474 475 476
		}
	}

477
	return res;
478 479
}

480 481 482
/*!
 * \brief Get timestamp of next key event.
 */
483
knot_time_t knot_get_next_zone_key_event(const zone_keyset_t *keyset)
484
{
485 486
	assert(keyset);

487
	knot_time_t result = 0;
488

489 490
	for (size_t i = 0; i < keyset->count; i++) {
		zone_key_t *key = &keyset->keys[i];
491
		if (knot_time_cmp(key->next_event, result) < 0) {
492 493
			result = key->next_event;
		}
494 495 496 497
	}

	return result;
}
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517

/*!
 * \brief Compute DS record rdata from key + cache it.
 */
int zone_key_calculate_ds(zone_key_t *for_key, dnssec_binary_t *out_donotfree)
{
	assert(for_key);
	assert(out_donotfree);

	int ret = KNOT_EOK;

	if (for_key->precomputed_ds.data == NULL) {
		dnssec_key_digest_t digesttype = DNSSEC_KEY_DIGEST_SHA256; // TODO !
		ret = dnssec_key_create_ds(for_key->key, digesttype, &for_key->precomputed_ds);
		ret = knot_error_from_libdnssec(ret);
	}

	*out_donotfree = for_key->precomputed_ds;
	return ret;
}