1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup dnskey DNSSEC keys functions
36 * @ingroup dnsdbdnssec
37 * @brief
38 *
39 * @{
40 */
41 /*------------------------------------------------------------------------------
42 *
43 * USE INCLUDES */
44 #include "dnsdb/dnsdb-config.h"
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <limits.h>
48 #include <string.h>
49 //#include <strings.h>
50 #include <arpa/inet.h>
51
52 #include <dnscore/thread.h>
53
54 #include <dnscore/base64.h>
55 #include <dnscore/format.h>
56 #include <dnscore/timeformat.h>
57 #include <dnscore/zalloc.h>
58 #include <dnscore/string_set.h>
59 #include <dnscore/file_input_stream.h>
60 #include <dnscore/dnskey-keyring.h>
61
62 #include <dnscore/ptr_set.h>
63 #include <dnscore/u32_set.h>
64
65 #include <dnscore/fdtools.h>
66 #include <sys/stat.h>
67
68 #include "dnsdb/zdb_error.h"
69 #include "dnsdb/zdb_record.h"
70
71 #include "dnsdb/dnssec.h"
72 #include "dnsdb/dnssec_config.h"
73 #include "dnsdb/dnssec-keystore.h"
74
75 #define MODULE_MSG_HANDLE g_dnssec_logger
76 extern logger_handle *g_dnssec_logger;
77
78 #ifndef PATH_MAX
79 #define PATH_MAX 4096
80 #endif
81
82 #define ZDB_KEYSTORE_ORIGIN_TAG 0x4e494749524f534b
83
84 #define OAT_PRIVATE_FORMAT "K%s+%03d+%05d.private"
85 #define OAT_DNSKEY_FORMAT "K%s+%03d+%05d.key"
86
87 // if the key is irrelevant and yadifad is self-managing, then a deactivated key can be removed after this time elapsed
88
89 #define AUTOMATIC_DEACTIVATED_DNSKEY_UNPUBLISH_DELAY 86400
90
91 static int dnssec_keystore_keys_node_compare(const void *, const void *);
92
93 #define DNSSEC_KEYSTORE_EMPTY {PTR_SET_CUSTOM(ptr_set_nullable_asciizp_node_compare), PTR_SET_CUSTOM(dnssec_keystore_keys_node_compare), PTR_SET_CUSTOM(ptr_set_nullable_dnsname_node_compare)/*, NULL*/, MUTEX_INITIALIZER}
94
95
96 //typedef btree dnssec_keystore;
97
98 /**
99 * After carefully weighting the advantages and disadvantages,
100 * the maintenance of the keys will go through a new keystore
101 *
102 * The keystore will contain all the paths it is supposed to scan and how many times a path has been added
103 * ie: once for the "global" setting, once for each zone it is specifically set on
104 * These paths are mandatory to avoid doing a lot of IOs when a simple scan can answer all our questions
105 *
106 * The keystore will contain all the keys by their name alg and tag.
107 * Probably something like tag + ( alg << 16 ), the idea being to use unassigned bits [9;14] of the flags
108 * Actually the name + tag should be enough.
109 *
110 * The keystore will contain a list of the keys for each zone, by their name
111 */
112
113 #define KSDOMAIN_TAG 0x4e49414d4f44534b
114
115 struct dnssec_keystore_domain_s
116 {
117 u8* fqdn; // domain name
118 u64 keys_scan_epoch; // last time the keys have been refreshed
119 const char *keys_path; // path where to find the keys of the domain
120 dnssec_key *key_chain; // list of keys for the domain
121 };
122
123 typedef struct dnssec_keystore_domain_s dnssec_keystore_domain_s;
124
125 struct dnssec_keystore
126 {
127 ptr_set paths; // path -> count : each path of the keystore and the number of domains using it
128 ptr_set keys; // name+alg+tag -> key
129 ptr_set domains; // name -> dnssec_keystore_domain_s
130 //const char *default_path;
131 mutex_t lock; // mutex
132 };
133
134 typedef struct dnssec_keystore dnssec_keystore;
135
136 static const char* g_keystore_path = DNSSEC_DEFAULT_KEYSTORE_PATH;
137 static dnssec_keystore g_keystore = DNSSEC_KEYSTORE_EMPTY;
138
139 #define KEY_HASH(key) ((((hashcode)key->tag)<<16)|key->flags|(key->algorithm<<1))
140 #define TAG_FLAGS_ALGORITHM_HASH(t_,f_,a_) ((((hashcode)t_)<<16)|(f_)|((a_)<<1))
141
142 static int
dnssec_keystore_keys_node_compare(const void * node_a,const void * node_b)143 dnssec_keystore_keys_node_compare(const void *node_a, const void *node_b)
144 {
145 dnssec_key *k_a = (dnssec_key*)node_a;
146 dnssec_key *k_b = (dnssec_key*)node_b;
147 ya_result ret;
148
149 ret = dnskey_get_algorithm(k_a) - dnskey_get_algorithm(k_b);
150
151 if(ret == 0)
152 {
153 ret = dnskey_get_tag(k_a) - dnskey_get_tag(k_b);
154
155 if(ret == 0)
156 {
157 ret = dnsname_compare(dnskey_get_domain(k_a), dnskey_get_domain(k_b));
158 }
159 }
160
161 return ret;
162 }
163
164 /**
165 *
166 * Initialises the keystore
167 *
168 * @param ks
169 */
170
171 void
dnssec_keystore_init()172 dnssec_keystore_init(/*dnssec_keystore *ks*/)
173 {
174 /*
175 dnssec_keystore *ks = &g_keystore;
176 ks->paths.root = NULL;
177 ks->paths.compare = ptr_set_nullable_asciizp_node_compare;
178 ks->keys.root = NULL;
179 ks->keys.compare = dnssec_keystore_keys_node_compare;
180 ks->domains.root = NULL;
181 ks->domains.compare = ptr_set_nullable_dnsname_node_compare;
182 mutex_init(&ks->lock);
183 */
184 }
185
186 static dnssec_keystore_domain_s*
dnssec_keystore_get_domain_nolock(dnssec_keystore * ks,const u8 * domain)187 dnssec_keystore_get_domain_nolock(dnssec_keystore *ks, const u8 *domain)
188 {
189 ptr_node *d_node = ptr_set_find(&ks->domains, domain);
190
191 return (dnssec_keystore_domain_s*)((d_node != NULL)?d_node->value:NULL);
192 }
193
194 static dnssec_keystore_domain_s*
dnssec_keystore_get_domain(dnssec_keystore * ks,const u8 * domain)195 dnssec_keystore_get_domain(dnssec_keystore *ks, const u8 *domain)
196 {
197 mutex_lock(&ks->lock);
198 dnssec_keystore_domain_s *ret = dnssec_keystore_get_domain_nolock(ks, domain); // locked
199 mutex_unlock(&ks->lock);
200 return ret;
201 }
202
203 /**
204 * Adds the knowledge of domain<->path
205 * Set path to NULL to use the default value
206 *
207 * Can overwrite a previous value
208 *
209 * @param ks
210 * @param domain
211 * @param path
212 */
213
214 static dnssec_keystore_domain_s*
dnssec_keystore_add_domain_nolock(dnssec_keystore * ks,const u8 * domain,const char * path)215 dnssec_keystore_add_domain_nolock(dnssec_keystore *ks, const u8 *domain, const char *path)
216 {
217 // insert or get the domain in the collection
218
219 ptr_node *d_node = ptr_set_insert(&ks->domains, (u8*)domain);
220 dnssec_keystore_domain_s *d;
221
222 if(d_node->value == NULL)
223 {
224 // insert : setup
225
226 ZALLOC_OBJECT_OR_DIE(d, dnssec_keystore_domain_s, KSDOMAIN_TAG);
227 d->fqdn = dnsname_zdup(domain);
228 d_node->key = d->fqdn;
229 d->keys_scan_epoch = 0;
230 d->keys_path = NULL;
231 d->key_chain = NULL;
232 d_node->value = d;
233 }
234 else
235 {
236 // get : has the keys path changed ?
237
238 d = (dnssec_keystore_domain_s*)d_node->value;
239
240 if(d->keys_path != NULL)
241 {
242 // tests for NULL or equality
243
244 if((path == d->keys_path) || ((path != NULL) && (strcmp(path, d->keys_path) == 0)))
245 {
246 // it has not changed : nothing to do
247 return d;
248 }
249
250 // it has changed : reduce previous count
251
252 ptr_node *node = ptr_set_find(&ks->paths, (char*)d->keys_path);
253 yassert(node != NULL);
254
255 node->value = (void*)(((intptr)node->value) - 1);
256
257 if(node->value == NULL)
258 {
259 char *key = (char*)node->key;
260 ptr_set_delete(&ks->paths, path);
261 free(key);
262 }
263
264 // the previous path is fully removed, the new value will be assigned, if needs to be, at the next step
265
266 d->keys_path = NULL;
267 d->keys_scan_epoch = 0;
268 }
269 }
270
271 if(path != NULL)
272 {
273 ptr_node *p_node = ptr_set_insert(&ks->paths, (char*)path);
274 if(p_node->value == NULL)
275 {
276 p_node->key = strdup(path);
277 }
278 p_node->value = (void*)(((intptr)p_node->value) + 1);
279
280 d->keys_path = (const char*)p_node->key;
281 d->keys_scan_epoch = 0;
282 }
283
284 return d;
285 }
286
287 void
dnssec_keystore_add_domain(const u8 * domain,const char * path)288 dnssec_keystore_add_domain(/*dnssec_keystore *ks, */const u8 *domain, const char *path)
289 {
290 dnssec_keystore *ks = &g_keystore;
291 mutex_lock(&ks->lock);
292 dnssec_keystore_add_domain_nolock(ks, domain, path);
293 mutex_unlock(&ks->lock);
294 }
295
296 /**
297 * Remove the knowledge of domain<->path
298 *
299 * @param ks
300 * @param domain
301 * @param path
302 */
303
304 void
dnssec_keystore_remove_domain_nolock(const u8 * domain,const char * path)305 dnssec_keystore_remove_domain_nolock(/*dnssec_keystore *ks, */const u8 *domain, const char *path)
306 {
307 (void)domain;
308 dnssec_keystore *ks = &g_keystore;
309 ptr_node *node = ptr_set_find(&ks->paths, path);
310 if(node != NULL)
311 {
312 node->value = (void*)(((intptr)node->value) - 1);
313
314 if(node->value == NULL)
315 {
316 char *key = (char*)node->key;
317 ptr_set_delete(&ks->paths, path);
318 free(key);
319 }
320 }
321 }
322
323 void
dnssec_keystore_remove_domain(const u8 * domain,const char * path)324 dnssec_keystore_remove_domain(/*dnssec_keystore *ks, */const u8 *domain, const char *path)
325 {
326 (void)domain;
327 dnssec_keystore *ks = &g_keystore;
328 mutex_lock(&ks->lock);
329 dnssec_keystore_remove_domain_nolock(domain, path);
330 mutex_unlock(&ks->lock);
331 }
332
333 /**
334 *
335 * Add a key to the keystore, do nothing if the key is already known
336 *
337 * RC ok
338 *
339 * @param ks
340 * @param key
341 */
342
343 static bool
dnssec_keystore_add_key_nolock(dnssec_keystore * ks,dnssec_key * key)344 dnssec_keystore_add_key_nolock(dnssec_keystore *ks, dnssec_key *key)
345 {
346 const u8 *domain = dnskey_get_domain(key);
347 dnssec_keystore_domain_s *kd;
348
349 kd = dnssec_keystore_get_domain_nolock(ks, domain); // caller nolock
350 if(kd == NULL)
351 {
352 kd = dnssec_keystore_add_domain_nolock(ks, domain, NULL);
353
354 yassert(kd != NULL);
355 }
356
357 // Add a reference in the keys collection
358
359
360 ptr_node *key_node = ptr_set_insert(&ks->keys, key);
361
362
363 if(key_node->value == NULL)
364 {
365 // new one
366 key_node->value = key;
367 dnskey_acquire(key); // RC
368
369 // Add a reference in the domain keys collection
370 // insert, sorted by tag value
371
372 dnskey_add_to_chain(key, &kd->key_chain); // RC
373
374 return TRUE;
375 }
376 // else already known
377
378 return FALSE;
379 }
380
381 /**
382 *
383 * Replace a key from the keystore, release the replaced key
384 *
385 * RC ok
386 *
387 * @param ks
388 * @param key
389 */
390
391 static bool
dnssec_keystore_replace_key_nolock(dnssec_keystore * ks,dnssec_key * key)392 dnssec_keystore_replace_key_nolock(dnssec_keystore *ks, dnssec_key *key)
393 {
394 const u8 *domain = dnskey_get_domain(key);
395 dnssec_keystore_domain_s *kd;
396
397 kd = dnssec_keystore_get_domain_nolock(ks, domain); // caller nolock
398 if(kd == NULL)
399 {
400 kd = dnssec_keystore_add_domain_nolock(ks, domain, NULL);
401
402 yassert(kd != NULL);
403 }
404
405 // Add a reference in the keys collection
406
407
408 ptr_node *key_node = ptr_set_insert(&ks->keys, key);
409
410
411 dnssec_key *old_key = (dnssec_key*)key_node->value;
412
413 if(old_key != key)
414 {
415 if(old_key != NULL)
416 {
417 dnskey_remove_from_chain(old_key, &kd->key_chain);
418 dnskey_release(old_key);
419 }
420
421 dnskey_acquire(key);
422 key_node->value = key;
423
424 // Add a reference in the domain keys collection
425 // insert, sorted by tag value
426
427 dnskey_add_to_chain(key, &kd->key_chain); // RC
428
429 return TRUE;
430 }
431 // else already known
432
433 return FALSE;
434 }
435
436
437 /**
438 *
439 * Add a key to the keystore, do nothing if a key with the same tag and algorithm is
440 * in the keystore for that domain already
441 *
442 * RC ok
443 *
444 * @param ks
445 * @param key
446 *
447 * @return TRUE iff the key was added
448 */
449
450 bool
dnssec_keystore_add_key(dnssec_key * key)451 dnssec_keystore_add_key(dnssec_key *key)
452 {
453 dnssec_keystore *ks = &g_keystore;
454 mutex_lock(&ks->lock);
455 bool ret = dnssec_keystore_add_key_nolock(ks, key); // RC // locked
456 mutex_unlock(&ks->lock);
457 return ret;
458 }
459
460 /**
461 *
462 * Replace a key from the keystore, release the replaced key
463 *
464 * RC ok
465 *
466 * @param ks
467 * @param key
468 *
469 * @return TRUE iff the key was added
470 */
471
472 bool
dnssec_keystore_replace_key(dnssec_key * key)473 dnssec_keystore_replace_key(dnssec_key *key)
474 {
475 dnssec_keystore *ks = &g_keystore;
476 mutex_lock(&ks->lock);
477 bool ret = dnssec_keystore_replace_key_nolock(ks, key); // RC // locked
478 mutex_unlock(&ks->lock);
479 return ret;
480 }
481
482 /**
483 *
484 * Removes a key from the keystore
485 * If the key is found, it is returned acquired (still has to be released)
486 *
487 * RC ok
488 *
489 * @param ks
490 * @param key
491 * @return the instance of the key from the keystore, or NULL if the key was not found
492 */
493
494 static dnssec_key*
dnssec_keystore_remove_key_nolock(dnssec_keystore * ks,dnssec_key * key)495 dnssec_keystore_remove_key_nolock(dnssec_keystore *ks, dnssec_key *key)
496 {
497 dnssec_key *ret_key = NULL;
498
499 ptr_node *key_node = ptr_set_find(&ks->keys, key);
500
501 if(key_node != NULL)
502 {
503 ret_key = (dnssec_key*)key_node->value;
504 ptr_set_delete(&ks->keys, key);
505 // no not release as it will be returned
506
507 const u8 *domain = dnskey_get_domain(key);
508
509 dnssec_keystore_domain_s *kd = dnssec_keystore_get_domain_nolock(ks, domain); // caller nolock
510
511 if(kd != NULL)
512 {
513 // remove, sorted by tag value
514
515 dnskey_remove_from_chain(key, &kd->key_chain); // RC
516 }
517 }
518 // else already known
519
520 return ret_key;
521 }
522
523 /**
524 *
525 * Removes a key from the keystore
526 * If the key is found, it is returned acquired (still requires release)
527 *
528 * RC ok
529 *
530 * @param ks
531 * @param key
532 *
533 * @return the instance of the key from the keystore, or NULL if the key was not found
534 */
535
536 dnssec_key*
dnssec_keystore_remove_key(dnssec_key * key)537 dnssec_keystore_remove_key(dnssec_key *key)
538 {
539 dnssec_keystore *ks = &g_keystore;
540 mutex_lock(&ks->lock);
541 dnssec_key *ret_key = dnssec_keystore_remove_key_nolock(ks, key); // RC // locked
542 mutex_unlock(&ks->lock);
543 return ret_key;
544 }
545
546 /**
547 * Removes a key from the keystore, if possible.
548 * Renames both key files adding suffix of the creation time plus bak
549 * Does not return any error code as it's a best effort kind of thing.
550 *
551 * @param key
552 */
553
554 void
dnssec_keystore_delete_key(dnssec_key * key)555 dnssec_keystore_delete_key(dnssec_key *key)
556 {
557 dnssec_keystore_domain_s *domain;
558 char clean_origin[MAX_DOMAIN_LENGTH];
559
560 const u8 *fqdn = key->owner_name;
561 const u8 algorithm = key->algorithm;
562 const u16 tag = key->tag;
563
564 /* Load from the disk, add to the keystore */
565
566 domain = dnssec_keystore_get_domain(&g_keystore, fqdn);
567 dnsname_to_cstr(clean_origin, fqdn);
568
569 format_writer epoch_writer = {packedepoch_format_handler_method, (void*)(intptr)key->epoch_created};
570
571 char path[PATH_MAX];
572 char path_new[PATH_MAX];
573
574 // PRIVATE
575
576 ya_result ret = SUCCESS;
577
578 if((domain != NULL) && (domain->keys_path != NULL))
579 {
580 if(snprintf(path, PATH_MAX, "%s/" OAT_PRIVATE_FORMAT, domain->keys_path, clean_origin, algorithm, tag) >= PATH_MAX)
581 {
582 /* Path bigger than PATH_MAX */
583 ret = BIGGER_THAN_PATH_MAX;
584 }
585 }
586 else
587 {
588 if(snprintf(path, PATH_MAX, "%s/" OAT_PRIVATE_FORMAT, g_keystore_path, clean_origin, algorithm, tag) >= PATH_MAX)
589 {
590 /* Path bigger than PATH_MAX */
591 ret = BIGGER_THAN_PATH_MAX;
592 }
593 }
594
595 if(ISOK(ret) && (snformat(path_new, sizeof(path_new), "%s.%w.bak", path, &epoch_writer) < PATH_MAX))
596 {
597 log_debug("dnskey-keystore: %{dnsname}: delete: private key file is '%s'", fqdn, path);
598
599 if(file_exists(path))
600 {
601 dnssec_key *key_from_file = NULL;
602
603 ret = dnskey_new_private_key_from_file(path, &key_from_file); // RC
604
605 if(ISOK(ret))
606 {
607 if(dnskey_equals(key, key_from_file))
608 {
609 log_info("dnskey-keystore: %{dnsname}: delete: private key file content matches key: renaming file '%s' to '%s'",
610 fqdn, path, path_new);
611
612 if(rename(path, path_new) < 0)
613 {
614 ret = ERRNO_ERROR;
615 log_err("dnskey-keystore: %{dnsname}: delete: could not rename file '%s' to '%s': %r",
616 fqdn, path, path_new, ret);
617 }
618 }
619 else
620 {
621 log_info("dnskey-keystore: %{dnsname}: delete: private key file content does not matches key: renaming file '%s' to '%s'",
622 fqdn, path, path_new);
623 }
624
625 dnskey_release(key_from_file);
626 key_from_file = NULL;
627 }
628 else
629 {
630 log_err("dnskey-keystore: %{dnsname}: delete: could not read key from private key file '%s': %r", fqdn, path, ret);
631 }
632 }
633 else
634 {
635 log_info("dnskey-keystore: %{dnsname}: delete: private key file '%s' does not exists", fqdn, path);
636 }
637 }
638 else
639 {
640 log_err("dnskey-keystore: %{dnsname}: delete: K%s+%03d+%05d private key file path size would be too big", fqdn, clean_origin, algorithm, tag);
641 }
642
643 // PUBLIC
644
645 ret = SUCCESS;
646
647 if((domain != NULL) && (domain->keys_path != NULL))
648 {
649 if(snprintf(path, PATH_MAX, "%s/" OAT_DNSKEY_FORMAT, domain->keys_path, clean_origin, algorithm, tag) >= PATH_MAX)
650 {
651 /* Path bigger than PATH_MAX */
652 ret = BIGGER_THAN_PATH_MAX;
653 }
654 }
655 else
656 {
657 if(snprintf(path, PATH_MAX, "%s/" OAT_DNSKEY_FORMAT, g_keystore_path, clean_origin, algorithm, tag) >= PATH_MAX)
658 {
659 /* Path bigger than PATH_MAX */
660 ret = BIGGER_THAN_PATH_MAX;
661 }
662 }
663
664 if(ISOK(ret) && (snformat(path_new, sizeof(path_new), "%s.%w.bak", path, &epoch_writer) < PATH_MAX))
665 {
666 log_debug("dnskey-keystore: %{dnsname}: delete: public key file is '%s'", fqdn, path);
667
668 if(file_exists(path))
669 {
670 dnssec_key *key_from_file = NULL;
671
672 ret = dnskey_new_public_key_from_file(path, &key_from_file); // RC
673
674 if(ISOK(ret))
675 {
676 if(dnskey_public_equals(key, key_from_file))
677 {
678 log_info("dnskey-keystore: %{dnsname}: delete: public key file content matches key: renaming file '%s' to '%s'", fqdn, path, path_new);
679
680 if(rename(path, path_new) < 0)
681 {
682 ret = ERRNO_ERROR;
683 log_err("dnskey-keystore: %{dnsname}: delete: could not rename file '%s' to '%s': %r", fqdn, path, path_new, ret);
684 }
685 }
686 else
687 {
688 log_info("dnskey-keystore: %{dnsname}: delete: public key file content does not matches key: renaming file '%s' to '%s'", fqdn, path, path_new);
689 }
690
691 dnskey_release(key_from_file);
692 key_from_file = NULL;
693 }
694 else
695 {
696 log_err("dnskey-keystore: %{dnsname}: delete: could not read key from public key file '%s': %r", fqdn, path, ret);
697 }
698 }
699 else
700 {
701 log_info("dnskey-keystore: %{dnsname}: delete: public key file '%s' does not exists", fqdn, path);
702 }
703 }
704 else
705 {
706 log_err("dnskey-keystore: %{dnsname}: delete: K%s+%03d+%05d public key file path size would be too big", fqdn, clean_origin, algorithm, tag);
707 }
708
709 dnssec_key *keystore_key = dnssec_keystore_remove_key(key);
710 if(keystore_key != NULL)
711 {
712 dnskey_release(keystore_key);
713 keystore_key = NULL;
714 }
715 }
716
717 /**
718 *
719 * Retrieves a key from the keystore
720 *
721 * RC ok
722 *
723 * @param ks
724 * @param domain
725 * @param tag
726 * @return
727 */
728
729 static dnssec_key*
dnssec_keystore_acquire_key_from_fqdn_nolock(dnssec_keystore * ks,const u8 * domain,u16 tag)730 dnssec_keystore_acquire_key_from_fqdn_nolock(dnssec_keystore *ks, const u8 *domain, u16 tag)
731 {
732 dnssec_key *key = NULL;
733
734 dnssec_keystore_domain_s* kd = dnssec_keystore_get_domain_nolock(ks, domain); // caller nolock
735 if(kd != NULL)
736 {
737 key = kd->key_chain;
738
739 while(key != NULL)
740 {
741 u16 key_tag = dnskey_get_tag(key);
742 if(key_tag == tag)
743 {
744 break;
745 }
746
747 key = key->next;
748 }
749
750 if(key != NULL)
751 {
752 dnskey_acquire(key);
753 }
754 }
755
756 return key;
757 }
758
759 /**
760 *
761 * Retrieves a key from the keystore
762 *
763 * RC ok
764 *
765 * @param ks
766 * @param domain
767 * @param tag
768 * @return
769 */
770
771 dnssec_key*
dnssec_keystore_acquire_key_from_fqdn_with_tag(const u8 * domain,u16 tag)772 dnssec_keystore_acquire_key_from_fqdn_with_tag(const u8 *domain, u16 tag)
773 {
774 dnssec_keystore *ks = &g_keystore;
775 mutex_lock(&ks->lock);
776 dnssec_key *key = dnssec_keystore_acquire_key_from_fqdn_nolock(ks, domain, tag); // RC // locked
777 mutex_unlock(&ks->lock);
778
779 return key;
780 }
781
782 /**
783 *
784 * Retrieves a key from the keystore
785 *
786 * RC ok
787 *
788 * @param ks
789 * @param domain
790 * @param tag
791 * @return
792 */
793
794 dnssec_key*
dnssec_keystore_acquire_key_from_rdata(const u8 * domain,const u8 * rdata,u16 rdata_size)795 dnssec_keystore_acquire_key_from_rdata(const u8 *domain, const u8 *rdata, u16 rdata_size)
796 {
797 dnssec_keystore *ks = &g_keystore;
798 u16 tag = dnskey_get_tag_from_rdata(rdata, rdata_size);
799 mutex_lock(&ks->lock);
800 dnssec_key *key = dnssec_keystore_acquire_key_from_fqdn_nolock(ks, domain, tag); // RC // locked
801 mutex_unlock(&ks->lock);
802
803 return key;
804 }
805
806 /**
807 * Returns the nth key from the domain or NULL if no such key exist
808 *
809 * RC ok
810 *
811 * @return a dnskey
812 */
813
814 dnssec_key*
dnssec_keystore_acquire_key_from_fqdn_by_index(const u8 * domain,int idx)815 dnssec_keystore_acquire_key_from_fqdn_by_index(const u8 *domain, int idx)
816 {
817 dnssec_keystore *ks = &g_keystore;
818 dnssec_key *key = NULL;
819 mutex_lock(&ks->lock);
820 dnssec_keystore_domain_s* kd = dnssec_keystore_get_domain_nolock(ks, domain); // locked
821 if(kd != NULL)
822 {
823 key = kd->key_chain;
824
825 while(idx > 0 && key != NULL)
826 {
827 --idx;
828 key = key->next;
829 }
830
831 if(key != NULL)
832 {
833 dnskey_acquire(key);
834 }
835 }
836 mutex_unlock(&ks->lock);
837
838 return key;
839 }
840
841 dnssec_key *
dnssec_keystore_acquire_key_from_fqdn_at_index(const u8 * domain,int index)842 dnssec_keystore_acquire_key_from_fqdn_at_index(const u8 *domain, int index)
843 {
844 dnssec_key *key = NULL;
845 dnssec_keystore *ks = &g_keystore;
846 mutex_lock(&ks->lock);
847 dnssec_keystore_domain_s *ks_domain = dnssec_keystore_get_domain_nolock(ks, domain); // locked
848 if(ks_domain != NULL)
849 {
850 key = ks_domain->key_chain;
851 while(index > 0 && key != NULL)
852 {
853 key = key->next;
854 --index;
855 }
856 if(key != NULL)
857 {
858 dnskey_acquire(key);
859 }
860 }
861 mutex_unlock(&ks->lock);
862 return key;
863 }
864
865 bool
dnssec_keystore_has_usable_ksk(const u8 * domain,time_t attime)866 dnssec_keystore_has_usable_ksk(const u8 *domain, time_t attime)
867 {
868 dnssec_keystore *ks = &g_keystore;
869 dnssec_key *key = NULL;
870 bool ret = FALSE;
871 mutex_lock(&ks->lock);
872 dnssec_keystore_domain_s* kd = dnssec_keystore_get_domain_nolock(ks, domain); // locked
873 if(kd != NULL)
874 {
875 key = kd->key_chain;
876
877 while(key != NULL)
878 {
879 if(dnskey_get_flags(key) == (DNSKEY_FLAG_ZONEKEY | DNSKEY_FLAG_KEYSIGNINGKEY))
880 {
881 if(dnskey_is_activated(key, attime))
882 {
883 ret = TRUE;
884 break;
885 }
886 }
887
888 key = key->next;
889 }
890 }
891
892 mutex_unlock(&ks->lock);
893
894 return ret;
895 }
896
897
898
899 int
dnssec_keystore_acquire_publish_delete_keys_from_fqdn_to_vectors(const u8 * domain,ptr_vector * publish_keys,ptr_vector * delete_keys)900 dnssec_keystore_acquire_publish_delete_keys_from_fqdn_to_vectors(const u8 *domain, ptr_vector *publish_keys, ptr_vector *delete_keys)
901 {
902 time_t now = time(NULL);
903
904 for(int i = 0; ;++i)
905 {
906 dnssec_key *key = dnssec_keystore_acquire_key_from_fqdn_by_index(domain, i);
907
908 if(key == NULL)
909 {
910 log_debug1("dnskey-keystore: acquiring activated key %{dnsname}: no other key available", domain);
911 break;
912 }
913
914 if((key->status & DNSKEY_KEY_IS_IN_ZONE) == 0)
915 {
916 if(dnskey_has_explicit_publish_or_delete(key))
917 {
918 if(dnskey_is_published(key, now))
919 {
920 if((publish_keys != NULL) && (ptr_vector_search_ptr_index(publish_keys, key) < 0))
921 {
922 ptr_vector_append(publish_keys, key);
923 }
924 else
925 {
926 dnskey_release(key);
927 }
928 continue;
929 }
930
931 if(dnskey_is_unpublished(key, now))
932 {
933 if((delete_keys != NULL) && (ptr_vector_search_ptr_index(delete_keys, key) < 0))
934 {
935 ptr_vector_append(delete_keys, key);
936 }
937 else
938 {
939 dnskey_release(key);
940 }
941 continue;
942 }
943 }
944 else if(dnskey_has_activate_or_deactivate(key))
945 {
946 if(dnskey_is_activated(key, now))
947 {
948 if((publish_keys != NULL) && (ptr_vector_search_ptr_index(publish_keys, key) < 0))
949 {
950 ptr_vector_append(publish_keys, key);
951 }
952 else
953 {
954 dnskey_release(key);
955 }
956 continue;
957 }
958 if(dnskey_is_deactivated(key, MAX((s64)now - AUTOMATIC_DEACTIVATED_DNSKEY_UNPUBLISH_DELAY, 0)))
959 {
960 if((delete_keys != NULL) && (ptr_vector_search_ptr_index(delete_keys, key) < 0))
961 {
962 ptr_vector_append(delete_keys, key);
963 }
964 else
965 {
966 dnskey_release(key);
967 }
968 continue;
969 }
970 }
971 }
972
973 dnskey_release(key);
974 }
975
976 int ret = 0;
977
978 if(publish_keys != NULL)
979 {
980 ret += ptr_vector_size(publish_keys);
981 }
982
983 if(delete_keys != NULL)
984 {
985 ret += ptr_vector_size(delete_keys);
986 }
987
988 return ret;
989 }
990
991 /**
992 * Releases all the keys from a vector.
993 *
994 * @param keys
995 */
996
997 void
dnssec_keystore_release_keys_from_vector(ptr_vector * keys)998 dnssec_keystore_release_keys_from_vector(ptr_vector *keys)
999 {
1000 for(int i = 0; i <= ptr_vector_last_index(keys); ++i)
1001 {
1002 dnssec_key *key = (dnssec_key*)ptr_vector_get(keys, i);
1003
1004 log_debug("dnskey-keystore: releasing key %{dnsname}", dnskey_get_domain(key));
1005
1006 dnskey_release(key);
1007 }
1008 }
1009
1010 /**
1011 *
1012 * Retrieves a key from the keystore
1013 *
1014 * RC ok
1015 *
1016 * @param ks
1017 * @param domain
1018 * @param tag
1019 * @return
1020 */
1021
1022 static dnssec_key*
dnssec_keystore_acquire_key_from_name_nolock(dnssec_keystore * ks,const char * domain,u16 tag)1023 dnssec_keystore_acquire_key_from_name_nolock(dnssec_keystore *ks, const char *domain, u16 tag)
1024 {
1025 dnssec_key *key = NULL;
1026 u8 fqdn[MAX_DOMAIN_LENGTH];
1027
1028 if(ISOK(cstr_to_dnsname(fqdn, domain)))
1029 {
1030 key = dnssec_keystore_acquire_key_from_fqdn_nolock(ks, fqdn, tag); // RC // caller nolock
1031 }
1032
1033 return key;
1034 }
1035
1036 /**
1037 *
1038 * Retrieves a key from the keystore
1039 *
1040 * RC ok
1041 *
1042 * @param ks
1043 * @param domain
1044 * @param tag
1045 * @return
1046 */
1047
1048 dnssec_key*
dnssec_keystore_acquire_key_from_name(const char * domain,u16 tag)1049 dnssec_keystore_acquire_key_from_name(const char *domain, u16 tag)
1050 {
1051 dnssec_key *key = NULL;
1052 u8 fqdn[MAX_DOMAIN_LENGTH];
1053
1054 if(ISOK(cstr_to_dnsname(fqdn, domain)))
1055 {
1056 key = dnssec_keystore_acquire_key_from_fqdn_with_tag(fqdn, tag); // RC
1057 }
1058
1059 return key;
1060 }
1061
1062 /**
1063 * Returns the nth key from the domain or NULL if no such key exist
1064 *
1065 * RC ok
1066 *
1067 * @return a dnskey
1068 */
1069
1070 dnssec_key *
dnssec_keystore_acquire_key_from_name_by_index(const char * domain,int idx)1071 dnssec_keystore_acquire_key_from_name_by_index(const char *domain, int idx)
1072 {
1073 dnssec_key *key = NULL;
1074 u8 fqdn[MAX_DOMAIN_LENGTH];
1075
1076 if(ISOK(cstr_to_dnsname(fqdn, domain)))
1077 {
1078 key = dnssec_keystore_acquire_key_from_fqdn_by_index(fqdn, idx); // RC
1079 }
1080
1081 return key;
1082 }
1083
1084 struct dnssec_keystore_reload_readdir_callback_s
1085 {
1086 dnssec_keystore *ks;
1087 const char *domain;
1088 int private_update;
1089 };
1090
1091 typedef struct dnssec_keystore_reload_readdir_callback_s dnssec_keystore_reload_readdir_callback_s;
1092
1093 static ya_result
dnssec_keystore_reload_readdir_callback_nolock(const char * basedir,const char * filename,u8 filetype,void * args_)1094 dnssec_keystore_reload_readdir_callback_nolock(const char *basedir, const char *filename, u8 filetype, void *args_)
1095 {
1096 //#define OAT_PRIVATE_FORMAT "K%s+%03d+%05d.private"
1097 //#define OAT_DNSKEY_FORMAT "K%s+%03d+%05d.key"
1098 if((filetype == DT_REG) && (filename[0] != 'K'))
1099 {
1100 return SUCCESS;
1101 }
1102
1103 dnssec_keystore_reload_readdir_callback_s *args = (dnssec_keystore_reload_readdir_callback_s*)args_;
1104
1105 dnssec_keystore *ks = args->ks;
1106
1107 int algorithm;
1108 int tag;
1109 char extension[16];
1110 char domain[256];
1111 char file[PATH_MAX + 1];
1112
1113 size_t dlen = strlen(basedir);
1114 size_t flen = strlen(filename);
1115
1116 if(dlen + flen >= sizeof(file))
1117 {
1118 log_err("path too long for '%s'/'%s'", basedir, filename);
1119 return INVALID_PATH;
1120 }
1121 memset(extension, 0, sizeof(extension)); // to shut-up valgrind
1122 memcpy(file, basedir, dlen);
1123 if(file[dlen - 1] != '/')
1124 {
1125 file[dlen++] = '/';
1126 }
1127 memcpy(&file[dlen], filename, flen + 1);
1128
1129 if(sscanf(filename, "K%255[^+]+%03d+%05d.%15s", domain, &algorithm, &tag, extension) == 4)
1130 {
1131 domain[255] = '\0'; // ensure the 256th char is '\0'
1132 if((args->domain == NULL) || (strcmp(domain, args->domain) == 0))
1133 {
1134 if(memcmp(extension, "private", 8) == 0)
1135 {
1136 log_debug("found private key file for domain '%s' with tag %i and algorithm %i", domain, tag, algorithm);
1137 s64 ts;
1138
1139 if(ISOK(file_mtime(file, &ts)))
1140 {
1141 // get the key with that domain/tag
1142 // @note 20150907 edf -- work in progress
1143
1144 dnssec_key *current_key = dnssec_keystore_acquire_key_from_name_nolock(ks, domain, tag); // RC // caller nolock
1145 if(current_key != NULL)
1146 {
1147 // check if it has to be reloaded
1148 if(current_key->timestamp >= ts)
1149 {
1150 // ignore this file (already got it)
1151
1152 dnskey_release(current_key);
1153
1154 return SUCCESS;
1155 }
1156
1157 log_info("DNSKEY from file '%s' was modified (expected %lT, got %lT)", filename, current_key->timestamp, ts);
1158 }
1159
1160 dnssec_key *key;
1161
1162 // remove the key from the keystore, load the key from disk
1163
1164 log_debug("dnssec_keystore_reload_readdir_callback: opening file '%s'", file);
1165
1166 ya_result ret;
1167
1168 if(ISOK(ret = dnskey_new_private_key_from_file(file, &key)))
1169 {
1170 bool is_missing_any_smart_field = !dnskey_has_explicit_publish_and_delete(key) || !dnskey_has_explicit_activate(key) || !dnskey_has_explicit_deactivate(key);
1171 bool has_no_smart_field = dnskey_has_explicit_publish_or_delete(key) && dnskey_has_explicit_activate(key) && dnskey_has_explicit_deactivate(key);
1172
1173 if(has_no_smart_field)
1174 {
1175 log_info("key from '%s' has no smart fields", file);
1176 }
1177 else if(is_missing_any_smart_field)
1178 {
1179 log_info("key from '%s' is missing some smart fields", file);
1180 }
1181 #if DEBUG
1182 log_debug1("dnssec_keystore_reload_readdir_callback: private key generated from file '%s'", file);
1183 #endif
1184 // compare the cryptographic parts of the key (the public key is enough) and
1185 // overwrite the timestamps iff they are the same, else ... refuse to break security
1186
1187 if(current_key != NULL)
1188 {
1189 if(dnskey_equals(current_key, key))
1190 {
1191 #if DEBUG
1192 log_debug1("dnssec_keystore_reload_readdir_callback: file '%s' has already been loaded", file);
1193 #endif
1194 current_key->epoch_created = key->epoch_created;
1195 current_key->epoch_publish = key->epoch_publish;
1196 current_key->epoch_activate = key->epoch_activate;
1197
1198 current_key->epoch_inactive = key->epoch_inactive;
1199 current_key->epoch_delete = key->epoch_delete;
1200 current_key->timestamp = key->timestamp;
1201 current_key->status &= ~(DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH|DNSKEY_KEY_HAS_SMART_FIELD_DELETE|DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE|DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE);
1202 current_key->status |= key->status & (DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH|DNSKEY_KEY_HAS_SMART_FIELD_DELETE|DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE|DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE);
1203 }
1204 else
1205 {
1206 // update
1207 #if DEBUG
1208 log_debug1("dnssec_keystore_reload_readdir_callback: file '%s' updated a key", file);
1209 #endif
1210 current_key->epoch_created = key->epoch_created;
1211 current_key->epoch_publish = key->epoch_publish;
1212 current_key->epoch_activate = key->epoch_activate;
1213
1214 current_key->epoch_inactive = key->epoch_inactive;
1215 current_key->epoch_delete = key->epoch_delete;
1216 current_key->timestamp = key->timestamp;
1217
1218 current_key->status &= ~(DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH|DNSKEY_KEY_HAS_SMART_FIELD_DELETE|DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE|DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE);
1219 current_key->status |= key->status & (DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH|DNSKEY_KEY_HAS_SMART_FIELD_DELETE|DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE|DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE);
1220
1221 // update key re-signature scheduling
1222 }
1223
1224 dnskey_release(current_key);
1225 }
1226 else
1227 {
1228 // add the new key
1229 #if DEBUG
1230 log_debug1("dnssec_keystore_reload_readdir_callback: file '%s' generated a new key", file);
1231 #endif
1232 dnssec_keystore_add_key_nolock(ks, key); // RC // caller nolock
1233
1234 // also : the key should be put in the zone and signature should be scheduled
1235 }
1236
1237 dnskey_release(key);
1238 ++args->private_update; // one key was modified (it's timings at the very least)
1239 #if DEBUG
1240 log_debug1("dnssec_keystore_reload_readdir_callback: file '%s' successfully read", file);
1241 #endif
1242 }
1243 else
1244 {
1245 log_debug("could not read '%s': %r (missing public .key file ?)", file, ret);
1246 }
1247 }
1248 else
1249 {
1250 log_err("could not access '%s': %r", file, ERRNO_ERROR);
1251 }
1252 } // else this is not a private key file
1253 }
1254 else
1255 {
1256 log_debug("ignoring key file %s (%s != %s)", filename, domain, args->domain);
1257 }
1258 }
1259 else
1260 {
1261 log_debug("ignoring file %s", filename);
1262 }
1263
1264 return SUCCESS; // invalid file name, but it's irrelevant for this
1265 }
1266
1267 /**
1268 *
1269 * (Re)loads keys found in the paths of the keystore
1270 *
1271 * @return
1272 */
1273
1274 ya_result
dnssec_keystore_reload()1275 dnssec_keystore_reload()
1276 {
1277 // scan all directories
1278
1279 // for each key found, load and propose it to the domain
1280 // if the key has changed ...
1281 // timings: remove the previous alarms (?)
1282 // removed: ?
1283 // added: update alarms (?)
1284
1285 dnssec_keystore *ks = &g_keystore;
1286 ya_result ret;
1287
1288 dnssec_keystore_reload_readdir_callback_s args = {ks, NULL, 0};
1289
1290 mutex_lock(&ks->lock);
1291
1292 ptr_set_iterator iter;
1293 ptr_set_iterator_init(&ks->paths, &iter);
1294 while(ptr_set_iterator_hasnext(&iter))
1295 {
1296 ptr_node *path_node = ptr_set_iterator_next_node(&iter);
1297 const char *path = (const char*)path_node->key;
1298 if(FAIL(ret = readdir_forall(path, dnssec_keystore_reload_readdir_callback_nolock, &args)))
1299 {
1300 log_err("dnssec keystore reload: an error occurred reading key directory '%s': %r", path, ret);
1301 }
1302 }
1303
1304 if(FAIL(ret = readdir_forall(g_keystore_path, dnssec_keystore_reload_readdir_callback_nolock, &args)))
1305 {
1306 log_err("dnssec keystore reload: an error occurred reading key directory '%s': %r", g_keystore_path, ret);
1307 }
1308
1309 mutex_unlock(&ks->lock);
1310
1311 if(ISOK(ret))
1312 {
1313 ret = args.private_update;
1314 }
1315
1316 return ret;
1317 }
1318
1319 /**
1320 *
1321 * (Re)loads keys found in the path of the keystore for the specified domain
1322 *
1323 * @param fqdn
1324 * @return
1325 */
1326
1327 ya_result
dnssec_keystore_reload_domain(const u8 * fqdn)1328 dnssec_keystore_reload_domain(const u8 *fqdn)
1329 {
1330 // scan all directories
1331
1332 // for each key found, load and propose it to the domain
1333 // if the key has changed ...
1334 // timings: remove the previous alarms (?)
1335 // removed: ?
1336 // added: update alarms (?)
1337
1338 log_debug("dnskey-keystore: %{dnsname}: reload domain: scanning for keys", fqdn);
1339
1340 dnssec_keystore *ks = &g_keystore;
1341 ya_result ret = SUCCESS;
1342
1343 mutex_lock(&ks->lock);
1344
1345 dnssec_keystore_domain_s *keystore_domain = dnssec_keystore_get_domain_nolock(ks, fqdn); // locked
1346
1347 ret = DNSSEC_ERROR_NO_KEY_FOR_DOMAIN; // no key for domain
1348
1349 if(keystore_domain != NULL)
1350 {
1351 char domain[MAX_DOMAIN_LENGTH];
1352
1353 dnsname_to_cstr(domain, fqdn);
1354
1355 dnssec_keystore_reload_readdir_callback_s args = {ks, domain, 0};
1356
1357 const char *path = keystore_domain->keys_path;
1358
1359 if(path == NULL)
1360 {
1361 path = g_keystore_path;
1362 }
1363
1364 struct stat st;
1365 stat(path, &st);
1366 #if defined WIN32
1367 s64 mod_time = st.st_mtime;
1368 #elif IS_DARWIN_OS
1369 s64 mod_time = st.st_mtimespec.tv_sec;
1370 mod_time *= 1000000000LL;
1371 mod_time += st.st_mtimespec.tv_nsec;
1372 #else
1373 s64 mod_time = st.st_mtim.tv_sec;
1374 mod_time *= 1000000000LL;
1375 mod_time += st.st_mtim.tv_nsec;
1376 #endif
1377
1378 if((u64)mod_time > keystore_domain->keys_scan_epoch)
1379 {
1380 if(ISOK(ret = readdir_forall(path, dnssec_keystore_reload_readdir_callback_nolock, &args)))
1381 {
1382 ret = args.private_update;
1383
1384 keystore_domain->keys_scan_epoch = mod_time;
1385 }
1386 else
1387 {
1388 log_err("dnssec keystore: %{dnsname} reload domain: an error occurred reading key directory '%s': %r", fqdn, path, ret);
1389
1390 if(keystore_domain->key_chain != NULL)
1391 {
1392 ret = 0;
1393 }
1394 }
1395 }
1396 else
1397 {
1398 log_debug("dnssec keystore: %{dnsname} reload domain: no need to scan key directory '%s' again", fqdn, path);
1399
1400 ret = 0;
1401 }
1402 }
1403
1404 mutex_unlock(&ks->lock);
1405
1406 return ret;
1407 }
1408
1409 // sanitises an origin
1410
1411 static void
dnssec_keystore_origin_copy_sanitize(char * target,const char * origin)1412 dnssec_keystore_origin_copy_sanitize(char* target, const char* origin)
1413 {
1414 if(origin == NULL)
1415 {
1416 target[0] = '.';
1417 target[1] = '\0';
1418 return;
1419 }
1420
1421 int origin_len = strlen(origin);
1422
1423 if(origin_len == 0)
1424 {
1425 target[0] = '.';
1426 target[1] = '\0';
1427 return;
1428 }
1429
1430 if(origin[origin_len - 1] == '.')
1431 {
1432 origin_len++;
1433 MEMCOPY(target, origin, origin_len);
1434 }
1435 else
1436 {
1437 MEMCOPY(target, origin, origin_len);
1438 target[origin_len++] = '.';
1439 target[origin_len] = '\0';
1440 }
1441 }
1442
1443 const char*
dnssec_keystore_getpath()1444 dnssec_keystore_getpath()
1445 {
1446 return g_keystore_path;
1447 }
1448
1449 static const char* dnssec_default_keystore_path = DNSSEC_DEFAULT_KEYSTORE_PATH;
1450
1451 void
dnssec_keystore_resetpath()1452 dnssec_keystore_resetpath()
1453 {
1454 /*
1455 * cast to void to avoid the -Wstring-compare warning
1456 */
1457
1458 if(((void*)g_keystore_path) != ((void*)dnssec_default_keystore_path))
1459 {
1460 free((void*)g_keystore_path);
1461 g_keystore_path = dnssec_default_keystore_path;
1462 }
1463 }
1464
1465 void
dnssec_keystore_setpath(const char * path)1466 dnssec_keystore_setpath(const char* path)
1467 {
1468 dnssec_keystore_resetpath();
1469
1470 if(path != NULL)
1471 {
1472 g_keystore_path = strdup(path);
1473 }
1474 }
1475 /*
1476 void
1477 dnssec_keystore_destroy_paths_cb(ptr_node *node)
1478 {
1479 free(node->key);
1480 }
1481 */
1482
1483 static void
dnssec_keystore_destroy_domains_cb(ptr_node * node)1484 dnssec_keystore_destroy_domains_cb(ptr_node *node)
1485 {
1486 dnssec_keystore_domain_s *d = (dnssec_keystore_domain_s*)node->value;
1487 dnsname_zfree(d->fqdn);
1488 d->fqdn = NULL;
1489 ZFREE_OBJECT(d);
1490 //d->keys_path is a pointer to a key in g_keystore.paths
1491 //d->key_chain should have been emptied by now
1492 }
1493
1494 void
dnssec_keystore_destroy()1495 dnssec_keystore_destroy()
1496 {
1497 log_debug("dnskey-keystore: clearing-up");
1498
1499 mutex_lock(&g_keystore.lock);
1500
1501 while(!ptr_set_isempty(&g_keystore.keys))
1502 {
1503 ptr_node *key_node = g_keystore.keys.root;
1504 dnssec_key *key = (dnssec_key *)key_node->key;
1505
1506 if(key != NULL)
1507 {
1508 log_debug("dnskey-keystore: %{dnsname} +%03d+%05d/%d status=%x rc=%i (%p)", dnskey_get_domain(key), key->algorithm, key->tag, ntohs(key->flags), key->status, key->rc, key);
1509
1510 dnssec_key *ret_key = dnssec_keystore_remove_key_nolock(&g_keystore, key); // locked
1511 dnskey_release(ret_key);
1512 }
1513 else
1514 {
1515 break;
1516 }
1517 }
1518
1519 ptr_set_callback_and_destroy(&g_keystore.domains, dnssec_keystore_destroy_domains_cb);
1520
1521 mutex_unlock(&g_keystore.lock);
1522 }
1523
1524
1525 /** Generates a private key, store in the keystore
1526 * The caller is supposed to create a resource record with this key and add
1527 * it to the owner.
1528 */
1529
1530 ya_result
dnssec_keystore_new_key(u8 algorithm,u32 size,u16 flags,const char * origin,dnssec_key ** out_key)1531 dnssec_keystore_new_key(u8 algorithm, u32 size, u16 flags, const char *origin, dnssec_key **out_key)
1532 {
1533 ya_result return_value;
1534
1535 dnssec_key* key = NULL;
1536
1537 char clean_origin[MAX_DOMAIN_LENGTH];
1538 u8 fqdn[MAX_DOMAIN_LENGTH];
1539
1540 /* sanitise the origin name */
1541
1542 dnssec_keystore_origin_copy_sanitize(clean_origin, origin);
1543 cstr_to_dnsname(fqdn, clean_origin);
1544
1545 /**
1546 * @note if 65536 keys exist then this function will loop forever
1547 */
1548
1549 for(;;)
1550 {
1551 switch(algorithm)
1552 {
1553 case DNSKEY_ALGORITHM_RSASHA1:
1554 case DNSKEY_ALGORITHM_RSASHA1_NSEC3:
1555 case DNSKEY_ALGORITHM_RSASHA256_NSEC3:
1556 case DNSKEY_ALGORITHM_RSASHA512_NSEC3:
1557 {
1558 if(FAIL(return_value = dnskey_rsa_newinstance(size, algorithm, flags, clean_origin, &key)))
1559 {
1560 return return_value;
1561 }
1562
1563 break;
1564 }
1565 case DNSKEY_ALGORITHM_DSASHA1:
1566 case DNSKEY_ALGORITHM_DSASHA1_NSEC3:
1567 {
1568 if(FAIL(return_value = dnskey_dsa_newinstance(size, algorithm, flags, clean_origin, &key)))
1569 {
1570 return return_value;
1571 }
1572
1573 break;
1574 }
1575 #if HAS_ECDSA_SUPPORT
1576 case DNSKEY_ALGORITHM_ECDSAP256SHA256:
1577 case DNSKEY_ALGORITHM_ECDSAP384SHA384:
1578 {
1579 if(FAIL(return_value = dnskey_ecdsa_newinstance(size, algorithm, flags, clean_origin, &key)))
1580 {
1581 return return_value;
1582 }
1583
1584 break;
1585 }
1586 #endif
1587 #if HAS_EDDSA_SUPPORT
1588 case DNSKEY_ALGORITHM_ED25519:
1589 case DNSKEY_ALGORITHM_ED448:
1590 {
1591 if(FAIL(return_value = dnskey_eddsa_newinstance(size, algorithm, flags, clean_origin, &key)))
1592 {
1593 return return_value;
1594 }
1595
1596 break;
1597 }
1598 #endif
1599 #ifdef DNSKEY_ALGORITHM_DUMMY
1600 case DNSKEY_ALGORITHM_DUMMY:
1601 {
1602 if(FAIL(return_value = dnskey_dummy_newinstance(size, algorithm, flags, clean_origin, &key)))
1603 {
1604 return return_value;
1605 }
1606 }
1607 #endif
1608 default:
1609 {
1610 return DNSSEC_ERROR_UNSUPPORTEDKEYALGORITHM;
1611 }
1612 }
1613
1614 dnssec_key *same_tag_key = NULL;
1615
1616 dnskey_get_tag(key); // updates the tag field if needed
1617
1618 if(ISOK(return_value = dnssec_keystore_load_private_key_from_parameters(algorithm, key->tag, flags, fqdn, &same_tag_key))) // key properly released
1619 {
1620 dnskey_release(same_tag_key);
1621 }
1622 else
1623 {
1624 // the key already exists
1625
1626 dnssec_keystore_store_private_key(key);
1627 dnssec_keystore_store_public_key(key);
1628
1629 dnssec_keystore_add_key(key);
1630 break;
1631 }
1632
1633 dnskey_release(key);
1634 }
1635
1636 *out_key = key;
1637
1638 return SUCCESS;
1639 }
1640
1641 /**
1642 * Loads a public key from the rdata, store in the keystore, then sets out_key to point to it
1643 *
1644 * RC ok
1645 *
1646 * @param rdata
1647 * @param rdata_size
1648 * @param origin
1649 * @param out_key
1650 * @return
1651 */
1652
1653 ya_result
dnssec_keystore_load_public_key_from_rdata(const u8 * rdata,u16 rdata_size,const u8 * fqdn,dnssec_key ** out_key)1654 dnssec_keystore_load_public_key_from_rdata(const u8 *rdata, u16 rdata_size, const u8 *fqdn, dnssec_key **out_key)
1655 {
1656 //u16 flags = DNSKEY_FLAGS_FROM_RDATA(rdata);
1657 //u8 algorithm = rdata[3];
1658
1659 u16 tag = dnskey_get_tag_from_rdata(rdata, rdata_size);
1660
1661 ya_result ret = SUCCESS;
1662
1663 dnssec_key *key = dnssec_keystore_acquire_key_from_fqdn_with_tag(fqdn, tag);
1664
1665 if(key == NULL)
1666 {
1667 if(ISOK(ret = dnskey_new_from_rdata(rdata, rdata_size, fqdn, &key))) // RC
1668 {
1669 if(!dnssec_keystore_add_key(key)) // RC
1670 {
1671 dnskey_release(key);
1672
1673 key = dnssec_keystore_acquire_key_from_fqdn_with_tag(fqdn, tag);
1674
1675 if(key == NULL) // should not happen
1676 {
1677 ret = ERROR;
1678 }
1679 }
1680 }
1681 }
1682
1683 *out_key = key; // already RCed at instantiation
1684
1685 return ret;
1686 }
1687
1688 /**
1689 * Loads a private key from the disk or the keystore, then returns it.
1690 * NOTE: If the key already existed as a public-only key, the public version is released.
1691 *
1692 * RC ok
1693 *
1694 * @param algorithm
1695 * @param tag
1696 * @param flags
1697 * @param origin
1698 * @param out_key
1699 * @return the number of keys loaded by the call (1 or 0) or an error code
1700 */
1701
1702 ya_result
dnssec_keystore_load_private_key_from_rdata(const u8 * rdata,u16 rdata_size,const u8 * fqdn,dnssec_key ** out_key)1703 dnssec_keystore_load_private_key_from_rdata(const u8 *rdata, u16 rdata_size, const u8 *fqdn, dnssec_key **out_key)
1704 {
1705 if(rdata_size < 4)
1706 {
1707 return INVALID_ARGUMENT_ERROR;
1708 }
1709
1710 u16 tag = dnskey_get_tag_from_rdata(rdata, rdata_size);
1711 u16 flags = GET_U16_AT_P(rdata);
1712 u8 algorithm = rdata[3];
1713
1714 ya_result ret = dnssec_keystore_load_private_key_from_parameters(algorithm, tag, flags, fqdn, out_key);
1715
1716 return ret;
1717 }
1718
1719 /**
1720 * Loads a private key from the disk or the keystore, then returns it.
1721 * NOTE: If the key already existed as a public-only key, the public version is released.
1722 *
1723 * RC ok
1724 *
1725 * @param algorithm
1726 * @param tag
1727 * @param flags
1728 * @param origin
1729 * @param out_key
1730 * @return SUCCESS if a key is loaded, 1 if the key was already loaded, or an error code
1731 */
1732
1733 ya_result
dnssec_keystore_load_private_key_from_parameters(u8 algorithm,u16 tag,u16 flags,const u8 * fqdn,dnssec_key ** out_key)1734 dnssec_keystore_load_private_key_from_parameters(u8 algorithm, u16 tag, u16 flags, const u8* fqdn, dnssec_key **out_key)
1735 {
1736 dnssec_key *key = dnssec_keystore_acquire_key_from_fqdn_with_tag(fqdn, tag);
1737 ya_result ret;
1738 bool has_public_key = FALSE;
1739
1740 *out_key = NULL;
1741
1742 if(key != NULL && !dnskey_is_private(key))
1743 {
1744 log_debug("dnssec_key_load_private: %{dnsname} +%03d+%05d/%d is not private", fqdn, algorithm, tag, ntohs(flags));
1745
1746 has_public_key = TRUE;
1747 dnskey_release(key);
1748 key = NULL;
1749 }
1750
1751 if(key == NULL)
1752 {
1753 // the key is not loaded already
1754
1755 dnssec_keystore_domain_s *domain;
1756 char clean_origin[MAX_DOMAIN_LENGTH];
1757 dnsname_to_cstr(clean_origin, fqdn);
1758
1759 /* Load from the disk, add to the keystore */
1760
1761 domain = dnssec_keystore_get_domain(&g_keystore, fqdn);
1762
1763 char path[PATH_MAX];
1764 path[0] = '\0';
1765
1766 if((domain != NULL) && (domain->keys_path != NULL))
1767 {
1768 if(snprintf(path, sizeof(path), "%s/" OAT_PRIVATE_FORMAT, domain->keys_path, clean_origin, algorithm, tag) >= PATH_MAX)
1769 {
1770 /* Path bigger than PATH_MAX */
1771 return BIGGER_THAN_PATH_MAX;
1772 }
1773 }
1774 else
1775 {
1776 if(snprintf(path, sizeof(path), "%s/" OAT_PRIVATE_FORMAT, g_keystore_path, clean_origin, algorithm, tag) >= PATH_MAX)
1777 {
1778 /* Path bigger than PATH_MAX */
1779 return BIGGER_THAN_PATH_MAX;
1780 }
1781 }
1782
1783 log_debug("dnssec_key_load_private: %{dnsname} +%03d+%05d/%d: opening file '%s'", fqdn, algorithm, tag, ntohs(flags), path);
1784
1785 ret = dnskey_new_private_key_from_file(path, &key); // RC
1786
1787 if(ISOK(ret))
1788 {
1789 if(has_public_key)
1790 {
1791 /*
1792 * remove the old (public) version
1793 */
1794
1795 log_debug("dnssec_key_load_private: %{dnsname} +%03d+%05hd/%hd: replacing previous version with loaded key", fqdn, algorithm, tag, ntohs(flags));
1796
1797 dnssec_keystore_replace_key(key); // RC
1798 }
1799 else
1800 {
1801 log_debug("dnssec_key_load_private: %{dnsname} +%03d+%05hd/%hd: adding loaded key", fqdn, algorithm, tag, ntohs(flags));
1802
1803 dnssec_keystore_add_key(key); // RC
1804 }
1805
1806 log_info("dnssec: loaded private key: %{dnsname} +%03d+%05hd/%hd from '%s'", fqdn, algorithm, tag, ntohs(flags), path);
1807
1808 *out_key = key;
1809 ret = 1; // newly loaded
1810 }
1811 else
1812 {
1813 log_debug("dnssec_key_load_private: %{dnsname} +%03d+%05hd/%hd: could not load the key: %r", fqdn, algorithm, tag, ntohs(flags), ret);
1814 }
1815 }
1816 else
1817 {
1818 *out_key = key;
1819 ret = 0; // already loaded
1820 }
1821
1822 return ret;
1823 }
1824
1825 ya_result
dnssec_keystore_store_private_key(dnssec_key * key)1826 dnssec_keystore_store_private_key(dnssec_key* key)
1827 {
1828 char path[PATH_MAX];
1829
1830 if(key == NULL || key->key.any == NULL || key->origin == NULL || !dnskey_is_private(key))
1831 {
1832 return DNSSEC_ERROR_INCOMPLETEKEY;
1833 }
1834
1835 dnskey_get_tag(key); // updates the tag field if needed
1836
1837 dnssec_keystore_domain_s *domain = dnssec_keystore_get_domain(&g_keystore, key->owner_name);
1838
1839 if((domain != NULL) && (domain->keys_path != NULL))
1840 {
1841 if(snprintf(path, sizeof(path), "%s/" OAT_PRIVATE_FORMAT, domain->keys_path, key->origin, key->algorithm, key->tag) >= PATH_MAX)
1842 {
1843 /* Path bigger than PATH_MAX */
1844 return DNSSEC_ERROR_KEYSTOREPATHISTOOLONG;
1845 }
1846 }
1847 else
1848 {
1849 if(snprintf(path, sizeof(path), "%s/" OAT_PRIVATE_FORMAT, g_keystore_path, key->origin, key->algorithm, key->tag) >= PATH_MAX)
1850 {
1851 /* Path bigger than PATH_MAX */
1852 return DNSSEC_ERROR_KEYSTOREPATHISTOOLONG;
1853 }
1854 }
1855
1856 switch(key->algorithm)
1857 {
1858 case DNSKEY_ALGORITHM_RSASHA1:
1859 case DNSKEY_ALGORITHM_RSASHA1_NSEC3:
1860 case DNSKEY_ALGORITHM_RSASHA256_NSEC3:
1861 case DNSKEY_ALGORITHM_RSASHA512_NSEC3:
1862 case DNSKEY_ALGORITHM_DSASHA1:
1863 case DNSKEY_ALGORITHM_DSASHA1_NSEC3:
1864 case DNSKEY_ALGORITHM_ECDSAP256SHA256:
1865 case DNSKEY_ALGORITHM_ECDSAP384SHA384:
1866 case DNSKEY_ALGORITHM_ED25519:
1867 case DNSKEY_ALGORITHM_ED448:
1868 #ifdef DNSKEY_ALGORITHM_DUMMY
1869 case DNSKEY_ALGORITHM_DUMMY:
1870 #endif
1871 {
1872 break;
1873 }
1874 default:
1875 {
1876 return DNSSEC_ERROR_UNSUPPORTEDKEYALGORITHM;
1877 }
1878 }
1879
1880 ya_result ret = dnskey_store_private_key_to_file(key, path);
1881
1882 return ret;
1883 }
1884
1885 ya_result
dnssec_keystore_store_public_key(dnssec_key * key)1886 dnssec_keystore_store_public_key(dnssec_key* key)
1887 {
1888 char path[PATH_MAX];
1889
1890 dnskey_get_tag(key); // updates the tag field if needed
1891
1892 dnssec_keystore_domain_s *domain = dnssec_keystore_get_domain(&g_keystore, key->owner_name);
1893
1894 if((domain != NULL) && (domain->keys_path != NULL))
1895 {
1896 if(snprintf(path, PATH_MAX, "%s/" OAT_DNSKEY_FORMAT, domain->keys_path, key->origin, key->algorithm, key->tag) >= PATH_MAX)
1897 {
1898 /* Path bigger than PATH_MAX */
1899 return DNSSEC_ERROR_KEYSTOREPATHISTOOLONG;
1900 }
1901 }
1902 else
1903 {
1904 if(snprintf(path, PATH_MAX, "%s/" OAT_DNSKEY_FORMAT, g_keystore_path, key->origin, key->algorithm, key->tag) >= PATH_MAX)
1905 {
1906 /* Path bigger than PATH_MAX */
1907 return DNSSEC_ERROR_KEYSTOREPATHISTOOLONG;
1908 }
1909 }
1910
1911 FILE* f;
1912
1913 if((f = fopen(path, "w+b")) == NULL)
1914 {
1915 return DNSSEC_ERROR_UNABLETOCREATEKEYFILES;
1916 }
1917
1918 u32 lc = 1;
1919 const char* p = key->origin;
1920 char c;
1921 while((c = *p) != '\0')
1922 {
1923 if(c == '.')
1924 {
1925 lc++;
1926 }
1927 p++;
1928 }
1929
1930 fprintf(f, "%s IN DNSKEY %u %u %u ", key->origin, ntohs(key->flags), lc, key->algorithm);
1931
1932 u8* rdata;
1933 u32 rdata_size = key->vtbl->dnssec_key_rdatasize(key);
1934
1935 MALLOC_OR_DIE(u8*, rdata, rdata_size, DNSKEY_RDATA_TAG);
1936
1937 /* store the RDATA */
1938
1939 key->vtbl->dnssec_key_writerdata(key, rdata, rdata_size);
1940
1941 char b64[BASE64_ENCODED_SIZE(4096)];
1942
1943 u8* ptr = rdata + 4;
1944 rdata_size -= 4;
1945 ya_result ret;
1946 u32 n = base64_encode(ptr, rdata_size, b64);
1947 if(fwrite(b64, n, 1, f) == 1)
1948 {
1949 ret = SUCCESS;
1950 }
1951 else
1952 {
1953 ret = DNSSEC_ERROR_KEYWRITEERROR;
1954 }
1955
1956 fprintf(f, "\n");
1957
1958 free(rdata);
1959
1960 fclose(f);
1961
1962 return ret;
1963 }
1964
1965 /**
1966 * Adds all the valid keys of the domain in the keyring
1967 *
1968 * @param fqdn the domain name
1969 * @param at_time the epoch at which the test is done ie: time(NULL)
1970 * @param kr the target keyring
1971 */
1972
1973 u32
dnssec_keystore_add_valid_keys_from_fqdn(const u8 * fqdn,time_t at_time,struct dnskey_keyring * kr)1974 dnssec_keystore_add_valid_keys_from_fqdn(const u8 *fqdn, time_t at_time, struct dnskey_keyring *kr)
1975 {
1976 dnssec_keystore *ks = &g_keystore;
1977 u32 count = 0;
1978 mutex_lock(&ks->lock);
1979 dnssec_keystore_domain_s *ks_domain = dnssec_keystore_get_domain_nolock(ks, fqdn); // locked
1980 if(ks_domain != NULL)
1981 {
1982 dnssec_key *key = ks_domain->key_chain;
1983
1984 while(key != NULL)
1985 {
1986 time_t from = (key->epoch_activate == 0)?1:key->epoch_activate;
1987 time_t to = (key->epoch_inactive == 0)?MAX_S32:key->epoch_inactive;
1988 if(from <= at_time && to >= at_time)
1989 {
1990 if(ISOK(dnskey_keyring_add(kr, key)))
1991 {
1992 ++count;
1993 }
1994 }
1995
1996 key = key->next;
1997 }
1998 }
1999 mutex_unlock(&ks->lock);
2000 return count;
2001 }
2002
2003 /**
2004 * Returns all the active keys, chained in a single linked list whose nodes need to be freed,
2005 *
2006 * @param zone
2007 * @param out_keys
2008 * @param out_ksk_count
2009 * @param out_zsk_count
2010 * @return
2011 */
2012
2013 ya_result
zdb_zone_get_active_keys(zdb_zone * zone,dnssec_key_sll ** out_keys,int * out_ksk_count,int * out_zsk_count)2014 zdb_zone_get_active_keys(zdb_zone *zone, dnssec_key_sll **out_keys, int *out_ksk_count, int *out_zsk_count)
2015 {
2016 ya_result ret = SUCCESS;
2017 int ksk_count = 0;
2018 int zsk_count = 0;
2019
2020 zdb_packed_ttlrdata* dnskey_rrset = zdb_record_find(&zone->apex->resource_record_set, TYPE_DNSKEY); // zone is locked
2021
2022 if(dnskey_rrset == NULL)
2023 {
2024 if(out_ksk_count != NULL)
2025 {
2026 *out_ksk_count = 0;
2027 }
2028
2029 if(out_zsk_count != NULL)
2030 {
2031 *out_zsk_count = 0;
2032 }
2033
2034 if(out_keys != NULL)
2035 {
2036 *out_keys = NULL;
2037 }
2038
2039 return DNSSEC_ERROR_RRSIG_NOZONEKEYS;
2040 }
2041
2042 dnssec_key_sll *keys = NULL;
2043
2044 for(zdb_packed_ttlrdata* key = dnskey_rrset ;key != NULL ;key = key->next)
2045 {
2046 u8 algorithm = DNSKEY_ALGORITHM(*key);
2047 u16 tag = DNSKEY_TAG(*key);
2048 u16 flags = DNSKEY_FLAGS(*key);
2049
2050 if((flags != DNSKEY_FLAGS_KSK) && (flags != DNSKEY_FLAGS_ZSK))
2051 {
2052 // ignore the key
2053 log_debug("rrsig: %{dnsname}: key with private key algorithm=%d tag=%05d flags=%3d is ignored (flags)", zone->origin, algorithm, tag, ntohs(flags));
2054
2055 continue;
2056 }
2057
2058 dnssec_key* priv_key;
2059 // from disk or from global keyring
2060 ret = dnssec_keystore_load_private_key_from_parameters(algorithm, tag, flags, zone->origin, &priv_key); // converted, key put in a collection or released
2061
2062 if(ISOK(ret))
2063 {
2064 yassert(priv_key != NULL);
2065
2066 if(dnskey_is_activated(priv_key, time(NULL)))
2067 {
2068 log_debug("rrsig: %{dnsname}: private key algorithm=%d tag=%05d flags=%3d is active", zone->origin, algorithm, tag, ntohs(flags));
2069
2070 /*
2071 * We can sign with this key : chain it
2072 */
2073
2074 if(flags == DNSKEY_FLAGS_KSK)
2075 {
2076 ++ksk_count;
2077 }
2078 else // flags == DNSKEY_FLAGS_ZSK
2079 {
2080 ++zsk_count;
2081 }
2082
2083 if(out_keys != NULL)
2084 {
2085 dnssec_key_sll *key_node;
2086 ZALLOC_OBJECT_OR_DIE(key_node, dnssec_key_sll, DNSSEC_KEY_SLL_TAG);
2087 key_node->next = keys;
2088 key_node->key = priv_key;
2089 keys = key_node;
2090 }
2091 else
2092 {
2093 dnskey_release(priv_key);
2094 }
2095 }
2096 else
2097 {
2098 log_debug("rrsig: %{dnsname}: private key algorithm=%d tag=%05d flags=%3d is not active", zone->origin, algorithm, tag, ntohs(flags));
2099 dnskey_release(priv_key);
2100 }
2101 }
2102 else
2103 {
2104 yassert(priv_key == NULL);
2105 }
2106 }
2107
2108 if(out_ksk_count != NULL)
2109 {
2110 *out_ksk_count = ksk_count;
2111 }
2112
2113 if(out_zsk_count != NULL)
2114 {
2115 *out_zsk_count = zsk_count;
2116 }
2117
2118 if(out_keys != NULL)
2119 {
2120 *out_keys = keys;
2121 }
2122
2123 ret = ksk_count + zsk_count;
2124
2125 return ret;
2126 }
2127
2128 /**
2129 *
2130 * @param keys
2131 */
2132
2133 void
zdb_zone_release_active_keys(dnssec_key_sll * keys)2134 zdb_zone_release_active_keys(dnssec_key_sll *keys)
2135 {
2136 while(keys != NULL)
2137 {
2138 dnskey_release(keys->key);
2139 dnssec_key_sll *tmp = keys;
2140 keys = keys->next;
2141 ZFREE_OBJECT(tmp);
2142 }
2143 }
2144
2145 /** @} */
2146