1 /*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 
3     This program is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  */
16 
17 #include <limits.h>
18 #include <string.h>
19 #include <strings.h>
20 #include <time.h>
21 #include <fcntl.h>
22 
23 #include "utils/keymgr/functions.h"
24 #include "utils/keymgr/bind_privkey.h"
25 #include "contrib/base64.h"
26 #include "contrib/color.h"
27 #include "contrib/ctype.h"
28 #include "contrib/string.h"
29 #include "contrib/strtonum.h"
30 #include "contrib/tolower.h"
31 #include "contrib/wire_ctx.h"
32 #include "libdnssec/error.h"
33 #include "libdnssec/keyid.h"
34 #include "libdnssec/shared/shared.h"
35 #include "knot/dnssec/kasp/policy.h"
36 #include "knot/dnssec/key-events.h"
37 #include "knot/dnssec/rrset-sign.h"
38 #include "knot/dnssec/zone-events.h"
39 #include "knot/dnssec/zone-keys.h"
40 #include "knot/dnssec/zone-sign.h"
41 #include "libzscanner/scanner.h"
42 
parse_timestamp(char * arg,knot_time_t * stamp)43 int parse_timestamp(char *arg, knot_time_t *stamp)
44 {
45 	int ret = knot_time_parse("YMDhms|'now'+-#u|'t'+-#u|+-#u|'t'+-#|+-#|#",
46 	                          arg, stamp);
47 	if (ret < 0) {
48 		ERROR("invalid timestamp: %s\n", arg);
49 		return KNOT_EINVAL;
50 	}
51 	return KNOT_EOK;
52 }
53 
init_timestamps(char * arg,knot_kasp_key_timing_t * timing)54 static bool init_timestamps(char *arg, knot_kasp_key_timing_t *timing)
55 {
56 	knot_time_t *dst = NULL;
57 
58 	if (strncasecmp(arg, "created=", 8) == 0) {
59 		dst = &timing->created;
60 	} else if (strncasecmp(arg, "publish=", 8) == 0) {
61 		dst = &timing->publish;
62 	} else if (strncasecmp(arg, "ready=", 6) == 0) {
63 		dst = &timing->ready;
64 	} else if (strncasecmp(arg, "active=", 7) == 0) {
65 		dst = &timing->active;
66 	} else if (strncasecmp(arg, "retire=", 7) == 0) {
67 		dst = &timing->retire;
68 	} else if (strncasecmp(arg, "remove=", 7) == 0) {
69 		dst = &timing->remove;
70 	} else if (strncasecmp(arg, "pre_active=", 11) == 0) {
71 		dst = &timing->pre_active;
72 	} else if (strncasecmp(arg, "post_active=", 12) == 0) {
73 		dst = &timing->post_active;
74 	} else if (strncasecmp(arg, "retire_active=", 14) == 0) {
75 		dst = &timing->retire_active;
76 	} else if (strncasecmp(arg, "revoke=", 7) == 0) {
77 		dst = &timing->revoke;
78 	} else {
79 		return false;
80 	}
81 
82 	knot_time_t stamp;
83 	int ret = parse_timestamp(strchr(arg, '=') + 1, &stamp);
84 	if (ret != KNOT_EOK) {
85 		return true;
86 	}
87 
88 	*dst = stamp;
89 
90 	return true;
91 }
92 
str2bool(const char * s)93 static bool str2bool(const char *s)
94 {
95 	switch (knot_tolower(s[0])) {
96 	case '1':
97 	case 'y':
98 	case 't':
99 		return true;
100 	default:
101 		return false;
102 	}
103 }
104 
bitmap_set(kdnssec_generate_flags_t * bitmap,int flag,bool onoff)105 static void bitmap_set(kdnssec_generate_flags_t *bitmap, int flag, bool onoff)
106 {
107         if (onoff) {
108                 *bitmap |= flag;
109         } else {
110                 *bitmap &= ~flag;
111         }
112 }
113 
genkeyargs(int argc,char * argv[],bool just_timing,kdnssec_generate_flags_t * flags,dnssec_key_algorithm_t * algorithm,uint16_t * keysize,knot_kasp_key_timing_t * timing,const char ** addtopolicy)114 static bool genkeyargs(int argc, char *argv[], bool just_timing,
115                        kdnssec_generate_flags_t *flags, dnssec_key_algorithm_t *algorithm,
116                        uint16_t *keysize, knot_kasp_key_timing_t *timing,
117                        const char **addtopolicy)
118 {
119 	// generate algorithms field
120 	char *algnames[256] = { 0 };
121 	algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA1] = "rsasha1";
122 	algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3] = "rsasha1nsec3sha1";
123 	algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA256] = "rsasha256";
124 	algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA512] = "rsasha512";
125 	algnames[DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256] = "ecdsap256sha256";
126 	algnames[DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384] = "ecdsap384sha384";
127 	algnames[DNSSEC_KEY_ALGORITHM_ED25519] = "ed25519";
128 	algnames[DNSSEC_KEY_ALGORITHM_ED448] = "ed448";
129 
130 	// parse args
131 	for (int i = 0; i < argc; i++) {
132 		if (!just_timing && strncasecmp(argv[i], "algorithm=", 10) == 0) {
133 			int alg = 256; // invalid value
134 			(void)str_to_int(argv[i] + 10, &alg, 0, 255);
135 			for (int al = 0; al < 256 && alg > 255; al++) {
136 				if (algnames[al] != NULL &&
137 				    strcasecmp(argv[i] + 10, algnames[al]) == 0) {
138 					alg = al;
139 				}
140 			}
141 			if (alg > 255) {
142 				ERROR("unknown algorithm: %s\n", argv[i] + 10);
143 				return false;
144 			}
145 			*algorithm = alg;
146 		} else if (strncasecmp(argv[i], "ksk=", 4) == 0) {
147 			bitmap_set(flags, DNSKEY_GENERATE_KSK, str2bool(argv[i] + 4));
148 		} else if (strncasecmp(argv[i], "zsk=", 4) == 0) {
149 			bitmap_set(flags, DNSKEY_GENERATE_ZSK, str2bool(argv[i] + 4));
150 		} else if (strncasecmp(argv[i], "sep=", 4) == 0) {
151 			bitmap_set(flags, DNSKEY_GENERATE_SEP_SPEC, true);
152 			bitmap_set(flags, DNSKEY_GENERATE_SEP_ON, str2bool(argv[i] + 4));
153 		} else if (!just_timing && strncasecmp(argv[i], "size=", 5) == 0) {
154 			if (str_to_u16(argv[i] + 5, keysize) != KNOT_EOK) {
155 				ERROR("invalid size: '%s'\n", argv[i] + 5);
156 				return false;
157 			}
158 		} else if (!just_timing && strncasecmp(argv[i], "addtopolicy=", 12) == 0) {
159 			*addtopolicy = argv[i] + 12;
160 		} else if (!init_timestamps(argv[i], timing)) {
161 			ERROR("invalid parameter: %s\n", argv[i]);
162 			return false;
163 		}
164 	}
165 
166 	return true;
167 }
168 
_check_lower(knot_time_t a,knot_time_t b,const char * a_name,const char * b_name)169 static bool _check_lower(knot_time_t a, knot_time_t b,
170 			 const char *a_name, const char *b_name)
171 {
172 	if (knot_time_cmp(a, b) > 0) {
173 		ERROR("semantic error: expected '%s' before '%s'\n", a_name, b_name);
174 		return false;
175 	}
176 	return true;
177 }
178 
179 #define check_lower(t, a, b) if (!_check_lower(t->a, t->b, #a, #b)) return KNOT_ESEMCHECK
180 
check_timers(const knot_kasp_key_timing_t * t)181 static int check_timers(const knot_kasp_key_timing_t *t)
182 {
183 	if (t->pre_active != 0) {
184 		check_lower(t, pre_active, publish);
185 	}
186 	check_lower(t, publish, active);
187 	check_lower(t, active, retire_active);
188 	check_lower(t, active, retire);
189 	check_lower(t, active, post_active);
190 	if (t->post_active == 0) {
191 		check_lower(t, retire, remove);
192 	}
193 	return KNOT_EOK;
194 }
195 
196 #undef check_lower
197 
198 // modifies ctx->policy options, so don't do anything afterwards !
keymgr_generate_key(kdnssec_ctx_t * ctx,int argc,char * argv[])199 int keymgr_generate_key(kdnssec_ctx_t *ctx, int argc, char *argv[])
200 {
201 	knot_time_t now = knot_time(), infty = 0;
202 	knot_kasp_key_timing_t gen_timing = { now, infty, now, infty, now, infty, infty, infty, infty };
203 	kdnssec_generate_flags_t flags = 0;
204 	uint16_t keysize = 0;
205 	const char *addtopolicy = NULL;
206 	if (!genkeyargs(argc, argv, false, &flags, &ctx->policy->algorithm,
207 			&keysize, &gen_timing, &addtopolicy)) {
208 		return KNOT_EINVAL;
209 	}
210 
211 	int ret = check_timers(&gen_timing);
212 	if (ret != KNOT_EOK) {
213 		return ret;
214 	}
215 
216 	if ((flags & DNSKEY_GENERATE_KSK) && gen_timing.ready == infty) {
217 		gen_timing.ready = gen_timing.active;
218 	}
219 
220 	if (keysize == 0) {
221 		keysize = dnssec_algorithm_key_size_default(ctx->policy->algorithm);
222 	}
223 	if ((flags & DNSKEY_GENERATE_KSK)) {
224 		ctx->policy->ksk_size = keysize;
225 	} else {
226 		ctx->policy->zsk_size = keysize;
227 	}
228 
229 	for (size_t i = 0; i < ctx->zone->num_keys; i++) {
230 		knot_kasp_key_t *kasp_key = &ctx->zone->keys[i];
231 		if ((kasp_key->is_ksk && (flags & DNSKEY_GENERATE_KSK)) &&
232 		    dnssec_key_get_algorithm(kasp_key->key) != ctx->policy->algorithm) {
233 			printf("warning: creating key with different algorithm than "
234 			       "configured in the policy\n");
235 			break;
236 		}
237 	}
238 
239 	knot_kasp_key_t *key = NULL;
240 	ret = kdnssec_generate_key(ctx, flags, &key);
241 	if (ret != KNOT_EOK) {
242 		return ret;
243 	}
244 
245 	key->timing = gen_timing;
246 
247 	if (addtopolicy != NULL) {
248 		char *last_policy_last = NULL;
249 
250 		knot_dname_t *unused = NULL;
251 		ret = kasp_db_get_policy_last(ctx->kasp_db, addtopolicy, &unused,
252 		                              &last_policy_last);
253 		knot_dname_free(unused, NULL);
254 		if (ret != KNOT_EOK && ret != KNOT_ENOENT) {
255 			free(last_policy_last);
256 			return ret;
257 		}
258 
259 		ret = kasp_db_set_policy_last(ctx->kasp_db, addtopolicy, last_policy_last,
260 		                              ctx->zone->dname, key->id);
261 		free(last_policy_last);
262 		if (ret != KNOT_EOK) {
263 			return ret;
264 		}
265 	}
266 
267 	ret = kdnssec_ctx_commit(ctx);
268 
269 	if (ret == KNOT_EOK) {
270 		printf("%s\n", key->id);
271 	}
272 
273 	return ret;
274 }
275 
parse_record(zs_scanner_t * scanner)276 static void parse_record(zs_scanner_t *scanner)
277 {
278 	dnssec_key_t *key = scanner->process.data;
279 
280 	if (dnssec_key_get_dname(key) != NULL ||
281 	    scanner->r_type != KNOT_RRTYPE_DNSKEY) {
282 		scanner->state = ZS_STATE_STOP;
283 		return;
284 	}
285 
286 	dnssec_binary_t rdata = {
287 		.data = scanner->r_data,
288 		.size = scanner->r_data_length
289 	};
290 	dnssec_key_set_dname(key, scanner->dname);
291 	dnssec_key_set_rdata(key, &rdata);
292 }
293 
bind_pubkey_parse(const char * filename,dnssec_key_t ** key_ptr)294 int bind_pubkey_parse(const char *filename, dnssec_key_t **key_ptr)
295 {
296 	dnssec_key_t *key = NULL;
297 	int result = dnssec_key_new(&key);
298 	if (result != DNSSEC_EOK) {
299 		return KNOT_ENOMEM;
300 	}
301 
302 	uint16_t cls = KNOT_CLASS_IN;
303 	uint32_t ttl = 0;
304 	zs_scanner_t *scanner = malloc(sizeof(zs_scanner_t));
305 	if (scanner == NULL) {
306 		dnssec_key_free(key);
307 		return KNOT_ENOMEM;
308 	}
309 
310 	if (zs_init(scanner, ".", cls, ttl) != 0 ||
311 	    zs_set_input_file(scanner, filename) != 0 ||
312 	    zs_set_processing(scanner, parse_record, NULL, key) != 0 ||
313 	    zs_parse_all(scanner) != 0) {
314 		int ret;
315 		switch (scanner->error.code) {
316 		case ZS_FILE_OPEN:
317 		case ZS_FILE_INVALID:
318 			ret = KNOT_EFILE;
319 			break;
320 		default:
321 			ret = KNOT_EPARSEFAIL;
322 		}
323 		zs_deinit(scanner);
324 		free(scanner);
325 		dnssec_key_free(key);
326 		return ret;
327 	}
328 	zs_deinit(scanner);
329 	free(scanner);
330 
331 	if (dnssec_key_get_dname(key) == NULL) {
332 		dnssec_key_free(key);
333 		return KNOT_INVALID_PUBLIC_KEY;
334 	}
335 
336 	*key_ptr = key;
337 	return KNOT_EOK;
338 }
339 
gen_keyfilename(const char * orig,const char * wantsuff,const char * altsuff)340 static char *gen_keyfilename(const char *orig, const char *wantsuff, const char *altsuff)
341 {
342 	assert(orig && wantsuff && altsuff);
343 
344 	const char *dot = strrchr(orig, '.');
345 
346 	if (dot != NULL && strcmp(dot, wantsuff) == 0) { // Full match.
347 		return strdup(orig);
348 	} else if (dot != NULL && strcmp(dot, altsuff) == 0) { // Replace suffix.
349 		return sprintf_alloc("%.*s%s", (int)(dot - orig), orig, wantsuff);
350 	} else { // Add wanted suffix.
351 		return sprintf_alloc("%s%s", orig, wantsuff);
352 	}
353 }
354 
keymgr_import_bind(kdnssec_ctx_t * ctx,const char * import_file,bool pub_only)355 int keymgr_import_bind(kdnssec_ctx_t *ctx, const char *import_file, bool pub_only)
356 {
357 	if (ctx == NULL || import_file == NULL) {
358 		return KNOT_EINVAL;
359 	}
360 
361 	knot_kasp_key_timing_t timing = { ctx->now, 0 };
362 	dnssec_key_t *key = NULL;
363 	char *keyid = NULL;
364 
365 	char *pubname = gen_keyfilename(import_file, ".key", ".private");
366 	if (pubname == NULL) {
367 		return KNOT_EINVAL;
368 	}
369 
370 	int ret = bind_pubkey_parse(pubname, &key);
371 	free(pubname);
372 	if (ret != KNOT_EOK) {
373 		goto fail;
374 	}
375 
376 	if (!pub_only) {
377 		bind_privkey_t bpriv = { .time_publish = ctx->now, .time_activate = ctx->now };
378 
379 		char *privname = gen_keyfilename(import_file, ".private", ".key");
380 		if (privname == NULL) {
381 			goto fail;
382 		}
383 
384 		ret = bind_privkey_parse(privname, &bpriv);
385 		free(privname);
386 		if (ret != DNSSEC_EOK) {
387 			goto fail;
388 		}
389 
390 		dnssec_binary_t pem = { 0 };
391 		ret = bind_privkey_to_pem(key, &bpriv, &pem);
392 		if (ret != DNSSEC_EOK) {
393 			bind_privkey_free(&bpriv);
394 			goto fail;
395 		}
396 
397 		bind_privkey_to_timing(&bpriv, &timing);
398 
399 		bind_privkey_free(&bpriv);
400 
401 		ret = dnssec_keystore_import(ctx->keystore, &pem, &keyid);
402 		dnssec_binary_free(&pem);
403 		if (ret != DNSSEC_EOK) {
404 			goto fail;
405 		}
406 	} else {
407 		timing.publish = ctx->now;
408 
409 		ret = dnssec_key_get_keyid(key, &keyid);
410 		if (ret != DNSSEC_EOK) {
411 			goto fail;
412 		}
413 	}
414 
415 	// allocate kasp key
416 	knot_kasp_key_t *kkey = calloc(1, sizeof(*kkey));
417 	if (!kkey) {
418 		ret = KNOT_ENOMEM;
419 		goto fail;
420 	}
421 
422 	kkey->id = keyid;
423 	kkey->key = key;
424 	kkey->timing = timing;
425 	kkey->is_pub_only = pub_only;
426 	kkey->is_ksk = (dnssec_key_get_flags(kkey->key) == DNSKEY_FLAGS_KSK);
427 	kkey->is_zsk = !kkey->is_ksk;
428 
429 	// append to zone
430 	ret = kasp_zone_append(ctx->zone, kkey);
431 	free(kkey);
432 	if (ret != KNOT_EOK) {
433 		goto fail;
434 	}
435 	ret = kdnssec_ctx_commit(ctx);
436 	if (ret == KNOT_EOK) {
437 		printf("%s\n", keyid);
438 		return KNOT_EOK;
439 	}
440 fail:
441 	dnssec_key_free(key);
442 	free(keyid);
443 	return knot_error_from_libdnssec(ret);
444 }
445 
import_key(kdnssec_ctx_t * ctx,unsigned backend,const char * param,int argc,char * argv[])446 static int import_key(kdnssec_ctx_t *ctx, unsigned backend, const char *param,
447                       int argc, char *argv[])
448 {
449 	if (ctx == NULL || param == NULL) {
450 		return KNOT_EINVAL;
451 	}
452 
453 	// parse params
454 	knot_time_t now = knot_time();
455 	knot_kasp_key_timing_t timing = { .publish = now, .active = now };
456 	kdnssec_generate_flags_t flags = 0;
457 	uint16_t keysize = 0;
458 	if (!genkeyargs(argc, argv, false, &flags, &ctx->policy->algorithm,
459 	                &keysize, &timing, NULL)) {
460 		return KNOT_EINVAL;
461 	}
462 
463 	int ret = check_timers(&timing);
464 	if (ret != KNOT_EOK) {
465 		return ret;
466 	}
467 
468 	normalize_generate_flags(&flags);
469 
470 	dnssec_key_t *key = NULL;
471 	char *keyid = NULL;
472 
473 	if (backend == KEYSTORE_BACKEND_PEM) {
474 		// open file
475 		int fd = open(param, O_RDONLY, 0);
476 		if (fd == -1) {
477 			return knot_map_errno();
478 		}
479 
480 		// determine size
481 		off_t fsize = lseek(fd, 0, SEEK_END);
482 		if (fsize == -1) {
483 			close(fd);
484 			return knot_map_errno();
485 		}
486 		if (lseek(fd, 0, SEEK_SET) == -1) {
487 			close(fd);
488 			return knot_map_errno();
489 		}
490 
491 		// alloc memory
492 		dnssec_binary_t pem = { 0 };
493 		ret = dnssec_binary_alloc(&pem, fsize);
494 		if (ret != DNSSEC_EOK) {
495 			close(fd);
496 			goto fail;
497 		}
498 
499 		// read pem
500 		ssize_t read_count = read(fd, pem.data, pem.size);
501 		close(fd);
502 		if (read_count == -1) {
503 			dnssec_binary_free(&pem);
504 			ret = knot_map_errno();
505 			goto fail;
506 		}
507 
508 		// put pem to kesytore
509 		ret = dnssec_keystore_import(ctx->keystore, &pem, &keyid);
510 		dnssec_binary_free(&pem);
511 		if (ret != DNSSEC_EOK) {
512 			goto fail;
513 		}
514 	} else {
515 		assert(backend == KEYSTORE_BACKEND_PKCS11);
516 		keyid = strdup(param);
517 	}
518 
519 	// create dnssec key
520 	ret = dnssec_key_new(&key);
521 	if (ret != DNSSEC_EOK) {
522 		goto fail;
523 	}
524 	ret = dnssec_key_set_dname(key, ctx->zone->dname);
525 	if (ret != DNSSEC_EOK) {
526 		goto fail;
527 	}
528 	dnssec_key_set_flags(key, dnskey_flags(flags & DNSKEY_GENERATE_SEP_ON));
529 	dnssec_key_set_algorithm(key, ctx->policy->algorithm);
530 
531 	// fill key structure from keystore (incl. pubkey from privkey computation)
532 	ret = dnssec_keystore_get_private(ctx->keystore, keyid, key);
533 	if (ret != DNSSEC_EOK) {
534 		goto fail;
535 	}
536 
537 	// allocate kasp key
538 	knot_kasp_key_t *kkey = calloc(1, sizeof(*kkey));
539 	if (kkey == NULL) {
540 		ret = KNOT_ENOMEM;
541 		goto fail;
542 	}
543 	kkey->id = keyid;
544 	kkey->key = key;
545 	kkey->timing = timing;
546 	kkey->is_ksk = (flags & DNSKEY_GENERATE_KSK);
547 	kkey->is_zsk = (flags & DNSKEY_GENERATE_ZSK);
548 
549 	// append to zone
550 	ret = kasp_zone_append(ctx->zone, kkey);
551 	free(kkey);
552 	if (ret != KNOT_EOK) {
553 		goto fail;
554 	}
555 	ret = kdnssec_ctx_commit(ctx);
556 	if (ret == KNOT_EOK) {
557 		printf("%s\n", keyid);
558 		return KNOT_EOK;
559 	}
560 fail:
561 	dnssec_key_free(key);
562 	free(keyid);
563 	return knot_error_from_libdnssec(ret);
564 }
565 
keymgr_import_pem(kdnssec_ctx_t * ctx,const char * import_file,int argc,char * argv[])566 int keymgr_import_pem(kdnssec_ctx_t *ctx, const char *import_file, int argc, char *argv[])
567 {
568 	return import_key(ctx, KEYSTORE_BACKEND_PEM, import_file, argc, argv);
569 }
570 
keymgr_import_pkcs11(kdnssec_ctx_t * ctx,char * key_id,int argc,char * argv[])571 int keymgr_import_pkcs11(kdnssec_ctx_t *ctx, char *key_id, int argc, char *argv[])
572 {
573 	if (!dnssec_keyid_is_valid(key_id)) {
574 		return DNSSEC_INVALID_KEY_ID;
575 	}
576 	dnssec_keyid_normalize(key_id);
577 	return import_key(ctx, KEYSTORE_BACKEND_PKCS11, key_id, argc, argv);
578 }
579 
keymgr_nsec3_salt_print(kdnssec_ctx_t * ctx)580 int keymgr_nsec3_salt_print(kdnssec_ctx_t *ctx)
581 {
582 	dnssec_binary_t salt_bin;
583 	knot_time_t created;
584 	int ret = kasp_db_load_nsec3salt(ctx->kasp_db, ctx->zone->dname,
585 	                                 &salt_bin, &created);
586 	switch (ret) {
587 	case KNOT_EOK:
588 		printf("Current salt: ");
589 		if (salt_bin.size == 0) {
590 			printf("-");
591 		}
592 		for (size_t i = 0; i < salt_bin.size; i++) {
593 			printf("%02X", (unsigned)salt_bin.data[i]);
594 		}
595 		printf("\n");
596 		free(salt_bin.data);
597 		break;
598 	case KNOT_ENOENT:
599 		printf("-- no salt --\n");
600 		ret = KNOT_EOK;
601 		break;
602 	}
603 	return ret;
604 }
605 
keymgr_nsec3_salt_set(kdnssec_ctx_t * ctx,const char * new_salt)606 int keymgr_nsec3_salt_set(kdnssec_ctx_t *ctx, const char *new_salt)
607 {
608 	assert(new_salt);
609 
610 	dnssec_binary_t salt_bin = { 0 };
611 	if (strcmp(new_salt, "-") != 0) {
612 		salt_bin.data = hex_to_bin(new_salt, &salt_bin.size);
613 		if (salt_bin.data == NULL) {
614 			return KNOT_EMALF;
615 		}
616 	}
617 	if (salt_bin.size != ctx->policy->nsec3_salt_length) {
618 		printf("Warning: specified salt doesn't match configured "
619 		       "salt length (%d).\n",
620 		       (int)ctx->policy->nsec3_salt_length);
621 	}
622 	int ret = kasp_db_store_nsec3salt(ctx->kasp_db, ctx->zone->dname,
623 	                                  &salt_bin, knot_time());
624 	if (salt_bin.size > 0) {
625 		free(salt_bin.data);
626 	}
627 	return ret;
628 }
629 
keymgr_serial_print(kdnssec_ctx_t * ctx,kaspdb_serial_t type)630 int keymgr_serial_print(kdnssec_ctx_t *ctx, kaspdb_serial_t type)
631 {
632 	uint32_t serial = 0;
633 	int ret = kasp_db_load_serial(ctx->kasp_db, ctx->zone->dname,
634 	                              type, &serial);
635 	switch (ret) {
636 	case KNOT_EOK:
637 		printf("Current serial: %u\n", serial);
638 		break;
639 	case KNOT_ENOENT:
640 		printf("-- no serial --\n");
641 		ret = KNOT_EOK;
642 		break;
643 	}
644 	return ret;
645 }
646 
keymgr_serial_set(kdnssec_ctx_t * ctx,kaspdb_serial_t type,uint32_t new_serial)647 int keymgr_serial_set(kdnssec_ctx_t *ctx, kaspdb_serial_t type, uint32_t new_serial)
648 {
649 	return kasp_db_store_serial(ctx->kasp_db, ctx->zone->dname,
650 	                            type, new_serial);
651 }
652 
print_tsig(dnssec_tsig_algorithm_t mac,const char * name,const dnssec_binary_t * secret)653 static void print_tsig(dnssec_tsig_algorithm_t mac, const char *name,
654 		       const dnssec_binary_t *secret)
655 {
656 	assert(name);
657 	assert(secret);
658 
659 	const char *mac_name = dnssec_tsig_algorithm_to_name(mac);
660 	assert(mac_name);
661 
662 	// client format (as a comment)
663 	printf("# %s:%s:%.*s\n", mac_name, name, (int)secret->size, secret->data);
664 
665 	// server format
666 	printf("key:\n");
667 	printf("  - id: %s\n", name);
668 	printf("    algorithm: %s\n", mac_name);
669 	printf("    secret: %.*s\n", (int)secret->size, secret->data);
670 }
671 
keymgr_generate_tsig(const char * tsig_name,const char * alg_name,int bits)672 int keymgr_generate_tsig(const char *tsig_name, const char *alg_name, int bits)
673 {
674 	dnssec_tsig_algorithm_t alg = dnssec_tsig_algorithm_from_name(alg_name);
675 	if (alg == DNSSEC_TSIG_UNKNOWN) {
676 		return KNOT_INVALID_KEY_ALGORITHM;
677 	}
678 
679 	int optimal_bits = dnssec_tsig_optimal_key_size(alg);
680 	if (bits == 0) {
681 		bits = optimal_bits; // TODO review
682 	}
683 
684 	// round up bits to bytes
685 	bits = (bits + CHAR_BIT - 1) / CHAR_BIT * CHAR_BIT;
686 
687 	if (bits != optimal_bits) {
688 		printf("Notice: Optimal key size for %s is %d bits.",
689 		       dnssec_tsig_algorithm_to_name(alg), optimal_bits);
690 	}
691 	assert(bits % CHAR_BIT == 0);
692 
693 	_cleanup_binary_ dnssec_binary_t key = { 0 };
694 	int r = dnssec_binary_alloc(&key, bits / CHAR_BIT);
695 	if (r != DNSSEC_EOK) {
696 		ERROR("failed to allocate memory\n");
697 		return knot_error_from_libdnssec(r);
698 	}
699 
700 	r = gnutls_rnd(GNUTLS_RND_KEY, key.data, key.size);
701 	if (r != 0) {
702 		ERROR("failed to generate secret the key\n");
703 		return knot_error_from_libdnssec(r);
704 	}
705 
706 	_cleanup_binary_ dnssec_binary_t key_b64 = { 0 };
707 	r = dnssec_binary_to_base64(&key, &key_b64);
708 	if (r != DNSSEC_EOK) {
709 		ERROR("failed to convert the key to Base64\n");
710 		return knot_error_from_libdnssec(r);
711 	}
712 
713 	print_tsig(alg, tsig_name, &key_b64);
714 
715 	return KNOT_EOK;
716 }
717 
is_hex(const char * string)718 static bool is_hex(const char *string)
719 {
720 	for (const char *p = string; *p != '\0'; p++) {
721 		if (!is_xdigit(*p)) {
722 			return false;
723 		}
724 	}
725 	return (*string != '\0');
726 }
727 
keymgr_get_key(kdnssec_ctx_t * ctx,const char * key_spec,knot_kasp_key_t ** key)728 int keymgr_get_key(kdnssec_ctx_t *ctx, const char *key_spec, knot_kasp_key_t **key)
729 {
730 	// Check if type of key spec is prescribed.
731 	bool is_keytag = false, is_id = false;
732 	if (strncasecmp(key_spec, "keytag=", 7) == 0) {
733 		key_spec += 7;
734 		is_keytag = true;
735 	} else if (strncasecmp(key_spec, "id=", 3) == 0) {
736 		key_spec += 3;
737 		is_id = true;
738 	}
739 
740 	uint16_t keytag = 0;
741 	bool can_be_keytag = (str_to_u16(key_spec, &keytag) == KNOT_EOK);
742 	long spec_len = strlen(key_spec);
743 
744 	// Check if input is a valid key spec.
745 	if ((is_keytag && !can_be_keytag) ||
746 	    (is_id && !is_hex(key_spec)) ||
747 	    (!can_be_keytag && !is_hex(key_spec))) {
748 		ERROR("invalid key specification\n");
749 		return KNOT_EINVAL;
750 	}
751 
752 	*key = NULL;
753 	for (size_t i = 0; i < ctx->zone->num_keys; i++) {
754 		knot_kasp_key_t *candidate = &ctx->zone->keys[i];
755 
756 		bool keyid_match = strncmp(candidate->id, key_spec, spec_len) == 0; // May be just a prefix.
757 		bool keytag_match = can_be_keytag &&
758 		                    dnssec_key_get_keytag(candidate->key) == keytag;
759 
760 		// Terminate if found exact key ID match.
761 		if (keyid_match && !is_keytag && strlen(candidate->id) == spec_len) {
762 			*key = candidate;
763 			break;
764 		}
765 		// Check for key ID prefix or tag match.
766 		if ((is_keytag && keytag_match) || // Tag is prescribed.
767 		    (is_id && keyid_match) ||   // Key ID is prescribed.
768 		    ((!is_keytag && !is_id) && (keyid_match || keytag_match))) { // Nothing is prescribed.
769 			if (*key == NULL) {
770 				*key = candidate;
771 			} else {
772 				ERROR("key is not specified uniquely. Please use id=Full_Key_ID\n");
773 				return KNOT_EINVAL;
774 			}
775 		}
776 	}
777 	if (*key == NULL) {
778 		ERROR("key not found\n");
779 		return KNOT_ENOENT;
780 	}
781 	return KNOT_EOK;
782 }
783 
keymgr_foreign_key_id(char * argv[],knot_lmdb_db_t * kaspdb,knot_dname_t ** key_zone,char ** key_id)784 int keymgr_foreign_key_id(char *argv[], knot_lmdb_db_t *kaspdb, knot_dname_t **key_zone, char **key_id)
785 {
786 	*key_zone = knot_dname_from_str_alloc(argv[3]);
787 	if (*key_zone == NULL) {
788 		return KNOT_ENOMEM;
789 	}
790 	knot_dname_to_lower(*key_zone);
791 
792 	kdnssec_ctx_t kctx = { 0 };
793 	int ret = kdnssec_ctx_init(conf(), &kctx, *key_zone, kaspdb, NULL);
794 	if (ret != KNOT_EOK) {
795 		ERROR("failed to initialize zone %s (%s)\n", argv[0], knot_strerror(ret));
796 		free(*key_zone);
797 		*key_zone = NULL;
798 		return KNOT_ENOZONE;
799 	}
800 	knot_kasp_key_t *key;
801 	ret = keymgr_get_key(&kctx, argv[2], &key);
802 	if (ret == KNOT_EOK) {
803 		*key_id = strdup(key->id);
804 		if (*key_id == NULL) {
805 			ret = KNOT_ENOMEM;
806 		}
807 	}
808 	kdnssec_ctx_deinit(&kctx);
809 	return ret;
810 }
811 
keymgr_set_timing(knot_kasp_key_t * key,int argc,char * argv[])812 int keymgr_set_timing(knot_kasp_key_t *key, int argc, char *argv[])
813 {
814 	knot_kasp_key_timing_t temp = key->timing;
815 	kdnssec_generate_flags_t flags = ((key->is_ksk ? DNSKEY_GENERATE_KSK : 0) | (key->is_zsk ? DNSKEY_GENERATE_ZSK : 0));
816 
817 	if (genkeyargs(argc, argv, true, &flags, NULL, NULL, &temp, NULL)) {
818 		int ret = check_timers(&temp);
819 		if (ret != KNOT_EOK) {
820 			return ret;
821 		}
822 		key->timing = temp;
823 		if (key->is_ksk != (bool)(flags & DNSKEY_GENERATE_KSK) ||
824 		    key->is_zsk != (bool)(flags & DNSKEY_GENERATE_ZSK) ||
825 		    flags & DNSKEY_GENERATE_SEP_SPEC) {
826 			normalize_generate_flags(&flags);
827 			key->is_ksk = (flags & DNSKEY_GENERATE_KSK);
828 			key->is_zsk = (flags & DNSKEY_GENERATE_ZSK);
829 			return dnssec_key_set_flags(key->key, dnskey_flags(flags & DNSKEY_GENERATE_SEP_ON));
830 		}
831 		return KNOT_EOK;
832 	}
833 	return KNOT_EINVAL;
834 }
835 
836 typedef struct {
837 	const char *name;
838 	size_t offset;
839 } timer_ctx_t;
840 
841 static const timer_ctx_t timers[] = {
842 	{ "pre-active",    offsetof(knot_kasp_key_timing_t, pre_active) },
843 	{ "publish",       offsetof(knot_kasp_key_timing_t, publish) },
844 	{ "ready",         offsetof(knot_kasp_key_timing_t, ready) },
845 	{ "active",        offsetof(knot_kasp_key_timing_t, active) },
846 	{ "retire-active", offsetof(knot_kasp_key_timing_t, retire_active) },
847 	{ "retire",        offsetof(knot_kasp_key_timing_t, retire) },
848 	{ "post-active",   offsetof(knot_kasp_key_timing_t, post_active) },
849 	{ "revoke",        offsetof(knot_kasp_key_timing_t, revoke) },
850 	{ "remove",        offsetof(knot_kasp_key_timing_t, remove) },
851 	{ NULL }
852 };
853 
print_key_brief(const knot_kasp_key_t * key,keymgr_list_params_t * params)854 static void print_key_brief(const knot_kasp_key_t *key, keymgr_list_params_t *params)
855 {
856 	const bool c = params->color;
857 
858 	printf("%s %s%5u%s ",
859 	       key->id, COL_BOLD(c), dnssec_key_get_keytag(key->key), COL_RST(c));
860 
861 	printf("%s%s%s%s ",
862 	       COL_BOLD(c),
863 	       (key->is_ksk ? (key->is_zsk ? COL_YELW(c) : COL_RED(c)) : COL_GRN(c)),
864 	       (key->is_ksk ? (key->is_zsk ? "CSK" : "KSK") : "ZSK"),
865 	       COL_RST(c));
866 
867 	uint8_t alg = dnssec_key_get_algorithm(key->key);
868 	const knot_lookup_t *alg_info = knot_lookup_by_id(knot_dnssec_alg_names, alg);
869 	if (alg_info != NULL) {
870 		printf("%s", alg_info->name);
871 		if (alg <= KNOT_DNSSEC_ALG_RSASHA512) {
872 			printf("%s/%u%s", COL_DIM(c), dnssec_key_get_size(key->key), COL_RST(c));
873 		}
874 	} else {
875 		printf("ALGORITHM_%u", alg);
876 	}
877 
878 	if (key->is_pub_only) {
879 		printf(" %s%spublic-only%s", COL_BOLD(c), COL_MGNT(c), COL_RST(c));
880 	}
881 
882 	static char buf[100];
883 	knot_time_t now = knot_time();
884 	for (const timer_ctx_t *t = &timers[0]; t->name != NULL; t++) {
885 		knot_time_t *val = (void *)(&key->timing) + t->offset;
886 		if (*val == 0) {
887 			continue;
888 		}
889 		bool past = (knot_time_cmp(*val, now) <= 0);
890 		const char *UNDR = past ? COL_UNDR(c) : "";
891 		const char *BOLD = past ? "" : COL_BOLD(c);
892 		for (const timer_ctx_t *t2 = t + 1; past && t2->name != NULL; t2++) {
893 			knot_time_t *val2 = (void *)(&key->timing) + t2->offset;
894 			if (knot_time_cmp(*val2, now) <= 0) {
895 				UNDR = "";
896 				break;
897 			}
898 		}
899 		(void)knot_time_print(params->format, *val, buf, sizeof(buf));
900 		printf(" %s%s%s=%s%s%s", UNDR, t->name, COL_RST(c), BOLD, buf, COL_RST(c));
901 	}
902 	printf("\n");
903 }
904 
print_key_full(const knot_kasp_key_t * key,knot_time_print_t format)905 static void print_key_full(const knot_kasp_key_t *key, knot_time_print_t format)
906 {
907 	printf("%s ksk=%s zsk=%s tag=%05d algorithm=%-2d size=%-4u public-only=%s", key->id,
908 	       (key->is_ksk ? "yes" : "no "), (key->is_zsk ? "yes" : "no "),
909 	       dnssec_key_get_keytag(key->key), (int)dnssec_key_get_algorithm(key->key),
910 	       dnssec_key_get_size(key->key), (key->is_pub_only ? "yes" : "no "));
911 
912 	static char buf[100];
913 	for (const timer_ctx_t *t = &timers[0]; t->name != NULL; t++) {
914 		knot_time_t *val = (void *)(&key->timing) + t->offset;
915 		(void)knot_time_print(format, *val, buf, sizeof(buf));
916 		printf(" %s=%s", t->name, buf);
917 	}
918 	printf("\n");
919 }
920 
921 typedef struct {
922 	knot_time_t val;
923 	const knot_kasp_key_t *key;
924 } key_sort_item_t;
925 
key_sort(const void * a,const void * b)926 static int key_sort(const void *a, const void *b)
927 {
928 	const key_sort_item_t *key_a = a;
929 	const key_sort_item_t *key_b = b;
930 	return knot_time_cmp(key_a->val, key_b->val);
931 }
932 
keymgr_list_keys(kdnssec_ctx_t * ctx,keymgr_list_params_t * params)933 int keymgr_list_keys(kdnssec_ctx_t *ctx, keymgr_list_params_t *params)
934 {
935 	if (ctx->zone->num_keys == 0) {
936 		return KNOT_EOK;
937 	}
938 	if (params->brief) {
939 		key_sort_item_t items[ctx->zone->num_keys];
940 		for (size_t i = 0; i < ctx->zone->num_keys; i++) {
941 			knot_kasp_key_t *key = &ctx->zone->keys[i];
942 			items[i].key = key;
943 			if (knot_time_cmp(key->timing.pre_active, key->timing.publish) < 0) {
944 				items[i].val = key->timing.pre_active;
945 			} else {
946 				items[i].val = key->timing.publish;
947 			}
948 		}
949 		qsort(&items, ctx->zone->num_keys, sizeof(items[0]), key_sort);
950 		for (size_t i = 0; i < ctx->zone->num_keys; i++) {
951 			print_key_brief(items[i].key, params);
952 		}
953 	} else {
954 		for (size_t i = 0; i < ctx->zone->num_keys; i++) {
955 			knot_kasp_key_t *key = &ctx->zone->keys[i];
956 			print_key_full(key, params->format);
957 		}
958 	}
959 	return KNOT_EOK;
960 }
961 
print_ds(const knot_dname_t * dname,const dnssec_binary_t * rdata)962 static int print_ds(const knot_dname_t *dname, const dnssec_binary_t *rdata)
963 {
964 	wire_ctx_t ctx = wire_ctx_init(rdata->data, rdata->size);
965 	if (wire_ctx_available(&ctx) < 4) {
966 		return KNOT_EMALF;
967 	}
968 
969 	char *name = knot_dname_to_str_alloc(dname);
970 	if (!name) {
971 		return KNOT_ENOMEM;
972 	}
973 
974 	uint16_t keytag   = wire_ctx_read_u16(&ctx);
975 	uint8_t algorithm = wire_ctx_read_u8(&ctx);
976 	uint8_t digest_type = wire_ctx_read_u8(&ctx);
977 
978 	size_t digest_size = wire_ctx_available(&ctx);
979 
980 	printf("%s DS %d %d %d ", name, keytag, algorithm, digest_type);
981 	for (size_t i = 0; i < digest_size; i++) {
982 		printf("%02x", ctx.position[i]);
983 	}
984 	printf("\n");
985 
986 	free(name);
987 	return KNOT_EOK;
988 }
989 
create_and_print_ds(const knot_dname_t * zone_name,const dnssec_key_t * key,dnssec_key_digest_t digest)990 static int create_and_print_ds(const knot_dname_t *zone_name,
991 			       const dnssec_key_t *key, dnssec_key_digest_t digest)
992 {
993 	_cleanup_binary_ dnssec_binary_t rdata = { 0 };
994 	int r = dnssec_key_create_ds(key, digest, &rdata);
995 	if (r != DNSSEC_EOK) {
996 		return knot_error_from_libdnssec(r);
997 	}
998 
999 	return print_ds(zone_name, &rdata);
1000 }
1001 
keymgr_generate_ds(const knot_dname_t * dname,const knot_kasp_key_t * key)1002 int keymgr_generate_ds(const knot_dname_t *dname, const knot_kasp_key_t *key)
1003 {
1004 	static const dnssec_key_digest_t digests[] = {
1005 		DNSSEC_KEY_DIGEST_SHA256,
1006 		DNSSEC_KEY_DIGEST_SHA384,
1007 		0
1008 	};
1009 
1010 	int ret = KNOT_EOK;
1011 	for (int i = 0; digests[i] != 0 && ret == KNOT_EOK; i++) {
1012 		ret = create_and_print_ds(dname, key->key, digests[i]);
1013 	}
1014 
1015 	return ret;
1016 }
1017 
keymgr_generate_dnskey(const knot_dname_t * dname,const knot_kasp_key_t * key)1018 int keymgr_generate_dnskey(const knot_dname_t *dname, const knot_kasp_key_t *key)
1019 {
1020 	const dnssec_key_t *dnskey = key->key;
1021 
1022 	char *name = knot_dname_to_str_alloc(dname);
1023 	if (!name) {
1024 		return KNOT_ENOMEM;
1025 	}
1026 
1027 	uint16_t flags = dnssec_key_get_flags(dnskey);
1028 	uint8_t algorithm = dnssec_key_get_algorithm(dnskey);
1029 
1030 	dnssec_binary_t pubkey = { 0 };
1031 	int ret = dnssec_key_get_pubkey(dnskey, &pubkey);
1032 	if (ret != DNSSEC_EOK) {
1033 		free(name);
1034 		return knot_error_from_libdnssec(ret);
1035 	}
1036 
1037 	uint8_t *base64_output = NULL;
1038 	int len = knot_base64_encode_alloc(pubkey.data, pubkey.size, &base64_output);
1039 	if (len < 0) {
1040 		free(name);
1041 		return len;
1042 	}
1043 
1044 	printf("%s DNSKEY %u 3 %u %.*s\n", name, flags, algorithm, len, base64_output);
1045 
1046 	free(base64_output);
1047 	free(name);
1048 	return KNOT_EOK;
1049 }
1050 
keymgr_list_zones(knot_lmdb_db_t * kaspdb)1051 int keymgr_list_zones(knot_lmdb_db_t *kaspdb)
1052 {
1053 	list_t zones;
1054 	init_list(&zones);
1055 	int ret = kasp_db_list_zones(kaspdb, &zones);
1056 	if (ret != KNOT_EOK) {
1057 		return ret;
1058 	}
1059 
1060 	knot_dname_txt_storage_t buf;
1061 	ptrnode_t *node;
1062 	WALK_LIST(node, zones) {
1063 		printf("%s\n", knot_dname_to_str(buf, node->d, sizeof(buf)));
1064 	}
1065 	ptrlist_deep_free(&zones, NULL);
1066 	return KNOT_EOK;
1067 }
1068