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 #include "keyroll.h"
36 #include <dnscore/timems.h>
37 #include <dnscore/thread_pool.h>
38 #include <dnscore/dnskey-signature.h>
39 #include <dnscore/packet_reader.h>
40 #include <dnscore/dnskey-keyring.h>
41 #include <dnscore/packet_writer.h>
42 #include <dnscore/parsing.h>
43 #include <dnscore/file_output_stream.h>
44 #include <dnscore/buffer_output_stream.h>
45 #include <dnscore/file_input_stream.h>
46 #include <dnscore/base64.h>
47 #include <dnscore/parser.h>
48 #include <dnscore/zone_reader_text.h>
49 #include <dnscore/logger.h>
50 #include <dnsdb/dnssec-keystore.h>
51 #include <dnscore/server-setup.h>
52
53 #include "dnssec-policy.h"
54 #include "buildinfo.h"
55
56 #define TTL 86400
57 #define RRSIG_ANTEDATING 86400 // sign from the day before
58 #define DNSKEY_DEACTIVATION_MARGIN 86400
59
60 #define UPDATE_SUBCOMMAND_ADD 0
61 #define UPDATE_SUBCOMMAND_DELETE 1
62
63 #define RECORD_SIZE_MAX (2 + 1 + 1 + 4 + 4 + 4 + 2 + 256 + 1024)
64
65 #define MODULE_MSG_HANDLE g_keyroll_logger
66
67 #define NEXT_SIGNATURE_EPOCH_MARGIN 57 // one minute should be enough, and adding a non-minute multiple makes is easier to notice
68
69 logger_handle *g_keyroll_logger = LOGGER_HANDLE_SINK;
70
71 static bool keyroll_dryrun_mode = FALSE;
72
keyroll_deactivation_margin(u32 activate_epoch,u32 deactivate_epoch,u32 delete_epoch)73 u32 keyroll_deactivation_margin(u32 activate_epoch, u32 deactivate_epoch, u32 delete_epoch)
74 {
75 u32 margin;
76 #if 1
77 s64 total_activated_time = deactivate_epoch;
78 total_activated_time -= activate_epoch;
79 if(total_activated_time >= 0)
80 {
81 s64 total_lingering_time = delete_epoch;
82 total_lingering_time -= deactivate_epoch;
83
84 if(total_lingering_time < 0)
85 {
86 log_err("keyroll: inverted activated and deactivated epoch");
87
88 margin = DNSKEY_DEACTIVATION_MARGIN;
89 }
90 else if(total_lingering_time / 2 > DNSKEY_DEACTIVATION_MARGIN)
91 {
92 margin = DNSKEY_DEACTIVATION_MARGIN;
93 }
94 else
95 {
96 margin = total_lingering_time / 2;
97 }
98 }
99 else
100 {
101 log_err("keyroll: inverted activated and deactivated epoch");
102
103 margin = DNSKEY_DEACTIVATION_MARGIN;
104 }
105 #else
106 margin = 57;
107 #endif
108
109 u32 remainder = margin % 60;
110 margin -= remainder;
111 margin += 57;
112 if(margin < 60)
113 {
114 margin += 60;
115 }
116
117 log_debug("keyroll_deactivation_margin: %u", DNSKEY_DEACTIVATION_MARGIN);
118
119 return margin;
120 }
121
122 ya_result keyroll_step_delete(keyroll_step_t *step);
123
124 //static const char *token_delmiter = " \t\r\n";
125
keyroll_dns_resource_record_ptr_vector_qsort_callback(const void * a,const void * b)126 static int keyroll_dns_resource_record_ptr_vector_qsort_callback(const void *a, const void *b)
127 {
128 const dns_resource_record *ra = (const dns_resource_record*)a;
129 const dns_resource_record *rb = (const dns_resource_record*)b;
130
131 int ret = dns_resource_record_compare(ra, rb);
132
133 return ret;
134 }
135
136 void
keyroll_errors_register()137 keyroll_errors_register()
138 {
139 error_register(KEYROLL_ERROR_BASE, "KEYROLL_ERROR_BASE");
140 error_register(KEYROLL_EXPECTED_IDENTICAL_RECORDS, "KEYROLL_EXPECTED_IDENTICAL_RECORDS");
141 error_register(KEYROLL_EXPECTED_IDENTICAL_SIZE_RRSETS, "KEYROLL_EXPECTED_IDENTICAL_SIZE_RRSETS");
142 error_register(KEYROLL_EXPECTED_DNSKEY_OR_RRSIG, "KEYROLL_EXPECTED_DNSKEY_OR_RRSIG");
143 error_register(KEYROLL_UPDATE_SUBCOMMAND_ERROR, "KEYROLL_UPDATE_SUBCOMMAND_ERROR");
144 error_register(KEYROLL_HOLE_IN_TIMELINE, "KEYROLL_HOLE_IN_TIMELINE");
145 error_register(KEYROLL_MUST_REINITIALIZE, "KEYROLL_MUST_REINITIALIZE");
146 }
147
148 ya_result
keyroll_init(keyroll_t * keyroll,const u8 * domain,const char * plan_path,const char * keys_path,const host_address * server,bool generation_mode)149 keyroll_init(keyroll_t* keyroll, const u8 *domain, const char *plan_path, const char *keys_path, const host_address *server, bool generation_mode)
150 {
151 ya_result ret = SUCCESS;
152 memset(keyroll, 0, sizeof(keyroll_t));
153 keyroll->ksk_parameters.algorithm = DNSKEY_ALGORITHM_RSASHA256_NSEC3;
154 keyroll->ksk_parameters.size = /*4096*/2048;
155 keyroll->ksk_parameters.activate_after = 86400;
156 keyroll->ksk_parameters.deactivate_after = 86400 + 86400*366;
157 keyroll->ksk_parameters.delete_after = 86400 + 86400*366 + 86400;
158 keyroll->ksk_parameters.estimated_signing_time = 86400;
159 keyroll->zsk_parameters.algorithm = DNSKEY_ALGORITHM_RSASHA256_NSEC3;
160 keyroll->zsk_parameters.size = 2048;
161 keyroll->zsk_parameters.activate_after = 86400;
162 keyroll->zsk_parameters.deactivate_after = 86400 + 86400*31;
163 keyroll->zsk_parameters.delete_after = 86400 + 86400*31 + 86400;
164 keyroll->zsk_parameters.estimated_signing_time = 86400 * 7;
165
166 keyroll->update_apply_verify_retries = 60; // if an update wasn't applied successfully, retry CHECKING this amount of times
167 keyroll->update_apply_verify_retries_delay = 1; // time between the above retries
168 keyroll->match_verify_retries = 60; // if there is not match, retry checking this amount of times
169 keyroll->match_verify_retries_delay = 1; // time between the above retries
170
171 keyroll->generation_mode = generation_mode;
172
173 asformat(&keyroll->plan_path, "%s/%{dnsname}", plan_path, domain);
174
175 if(generation_mode)
176 {
177 if(FAIL(ret = mkdir_ex(keyroll->plan_path, 0700, 0)))
178 {
179 log_err("keyroll: %{dnsname}: could not create directory: '%s'", domain, keyroll->plan_path);
180 free(keyroll->plan_path);
181 keyroll->plan_path = NULL;
182 return ret;
183 }
184
185 asformat(&keyroll->private_keys_path, "%s/%{dnsname}" YKEYROLL_KSK_SUFFIX, plan_path, domain);
186
187 if(FAIL(ret = mkdir_ex(keyroll->private_keys_path, 0700, 0)))
188 {
189 log_err("keyroll: %{dnsname}: could not create directory: '%s'", domain, keyroll->private_keys_path);
190 free(keyroll->plan_path);
191 keyroll->plan_path = NULL;
192 free(keyroll->private_keys_path);
193 keyroll->private_keys_path = NULL;
194 return ret;
195 }
196
197 dnssec_keystore_add_domain(domain, keyroll->private_keys_path);
198 }
199 else
200 {
201 if(FAIL(ret = file_is_directory(keyroll->plan_path)))
202 {
203 log_err("keyroll: %{dnsname}: could not find directory: '%s'", domain, keyroll->plan_path);
204 }
205 }
206
207 keyroll->keys_path = strdup(keys_path);
208 keyroll->domain = dnsname_zdup(domain);
209 keyroll->domain = dnsname_zdup(domain);
210 keyroll->server = host_address_copy(server);
211 keyroll->keyring = dnskey_keyring_new();
212
213 return ret;
214 }
215
216 static void
keyroll_finalize_steps_delete_callback(u64_node * node)217 keyroll_finalize_steps_delete_callback(u64_node *node)
218 {
219 keyroll_step_t *step = (keyroll_step_t*)node->value;
220 keyroll_step_delete(step);
221 }
222
223 void
keyroll_finalize(keyroll_t * keyroll)224 keyroll_finalize(keyroll_t *keyroll)
225 {
226 if(keyroll != NULL)
227 {
228 free(keyroll->private_keys_path);
229 keyroll->private_keys_path = NULL;
230 free(keyroll->plan_path);
231 keyroll->plan_path = NULL;
232 free(keyroll->keys_path);
233 keyroll->keys_path = NULL;
234
235 if(keyroll->domain != NULL)
236 {
237 dnsname_zfree(keyroll->domain);
238 keyroll->domain = NULL;
239 }
240
241 if(keyroll->server != NULL)
242 {
243 host_address_delete(keyroll->server);
244 keyroll->server = NULL;
245 }
246
247 if(keyroll->keyring != NULL)
248 {
249 dnskey_keyring_free(keyroll->keyring);
250 keyroll->keyring = NULL;
251 }
252
253 u64_set_callback_and_destroy(&keyroll->steps, keyroll_finalize_steps_delete_callback);
254
255 memset(keyroll, 0, sizeof(keyroll_t));
256 }
257 }
258
259 ya_result
keyroll_fetch_public_keys_from_server(keyroll_t * keyroll)260 keyroll_fetch_public_keys_from_server(keyroll_t* keyroll)
261 {
262 ya_result ret;
263
264 const u8 *domain = keyroll->domain;
265 const host_address *server = keyroll->server;
266
267 /*
268 memset(keyroll, 0, sizeof(keyroll_t));
269
270 asformat(&keyroll->plan_path, "%s/%{dnsname}", plan_path, domain);
271 if(FAIL(ret = mkdir_ex(keyroll->plan_path, 0700, 0)))
272 {
273 free(keyroll->plan_path);
274 return ret;
275 }
276
277 keyroll->keys_path = strdup(keys_path);
278 keyroll->private_keys_path = strdup(private_keys_path);
279
280 dnssec_keystore_add_domain(domain, private_keys_path);
281 */
282 message_data *mesg = message_new_instance();
283 dnskey_keyring *keyring = keyroll->keyring;
284
285 //u8 fqdn[MAX_DOMAIN_LENGTH];
286 //message_set_edns0(mesg, TRUE);
287
288 message_make_query(mesg, rand(), domain, TYPE_DNSKEY, CLASS_IN);
289
290 if(ISOK(ret = message_query(mesg, server)))
291 {
292 // extract DNSKEY (and maybe their RRSIG)
293 struct packet_unpack_reader_data pr;
294 packet_reader_init_from_message(&pr, mesg);
295
296 // ensure there is exactly one answer
297 // skip the matching query content, or fail
298
299 if(ISOK(ret = (message_get_query_count(mesg) == 1)?SUCCESS:ERROR) &&
300 ISOK(ret = packet_reader_skip_query(&pr, domain, TYPE_DNSKEY, CLASS_IN)))
301 {
302 u16 answer_count = message_get_answer_count(mesg);
303
304 if(answer_count > 0)
305 {
306 size_t buffer_size = 0x20000;
307 u8 *buffer;
308 MALLOC_OBJECT_ARRAY_OR_DIE(buffer, u8, buffer_size, GENERIC_TAG);
309
310 dns_resource_record rr;
311 dns_resource_record_init(&rr);
312
313 for(u16 i = 0; i < answer_count; ++i)
314 {
315 if(FAIL(ret = packet_reader_read_dns_resource_record(&pr, &rr)))
316 {
317 break;
318 }
319
320 if(rr.tctr.qtype == TYPE_DNSKEY)
321 {
322 dnssec_key *key;
323 if(FAIL(ret = dnskey_new_from_rdata(rr.rdata, rr.rdata_size, domain, &key)))
324 {
325 break;
326 }
327
328 // got one key
329
330 if(FAIL(ret = dnskey_keyring_add(keyring, key)))
331 {
332 // e.g.: collision
333 dnskey_release(key);
334 }
335 }
336
337 dns_resource_record_clear(&rr);
338 }
339
340 dns_resource_record_finalize(&rr);
341
342 free(buffer);
343 }
344 }
345 }
346
347 message_free(mesg);
348
349 return ret;
350 }
351
352 ya_result
keyroll_init_from_server(keyroll_t * keyroll,const u8 * domain,const char * plan_path,const char * keys_path,const host_address * server)353 keyroll_init_from_server(keyroll_t* keyroll, const u8 *domain, const char *plan_path, const char *keys_path, const host_address *server)
354 {
355 ya_result ret;
356
357 if(FAIL(ret = keyroll_init(keyroll, domain, plan_path, keys_path, server, TRUE)))
358 {
359 return ret;
360 }
361
362 ret = keyroll_fetch_public_keys_from_server(keyroll);
363
364 if(FAIL(ret))
365 {
366 keyroll_finalize(keyroll);
367 }
368
369 return ret;
370 }
371
372 ya_result
keyroll_update_apply_verify_retries_set(keyroll_t * keyroll,u32 retries,u32 delay)373 keyroll_update_apply_verify_retries_set(keyroll_t* keyroll, u32 retries, u32 delay)
374 {
375 if(retries * delay < 3600)
376 {
377 keyroll->update_apply_verify_retries = retries;
378 keyroll->update_apply_verify_retries_delay = delay;
379 return SUCCESS;
380 }
381 else
382 {
383 return CONFIG_VALUE_OUT_OF_RANGE;
384 }
385 }
386
387 ya_result
keyroll_match_verify_retries_set(keyroll_t * keyroll,u32 retries,u32 delay)388 keyroll_match_verify_retries_set(keyroll_t* keyroll, u32 retries, u32 delay)
389 {
390 if(retries * delay < 3600)
391 {
392 keyroll->match_verify_retries = retries;
393 keyroll->match_verify_retries_delay = delay;
394 return SUCCESS;
395 }
396 else
397 {
398 return CONFIG_VALUE_OUT_OF_RANGE;
399 }
400 }
401
402 typedef struct keyroll_file_item_s
403 {
404 char *name;
405 u8 *data;
406 size_t size;
407 bool name_allocated;
408 bool data_allocated;
409 } keyroll_file_item_t;
410
411 typedef struct keyroll_file_s
412 {
413 u8 *data;
414 size_t data_size;
415 output_stream baos;
416 input_stream bais;
417 } keyroll_file_t;
418
keyroll_file_init(keyroll_file_t * kf)419 void keyroll_file_init(keyroll_file_t *kf)
420 {
421 kf->data = NULL;
422 kf->data_size = 0;
423 output_stream_set_void(&kf->baos);
424 input_stream_set_void(&kf->bais);
425 }
426
keyroll_file_write_start(keyroll_file_t * kf)427 void keyroll_file_write_start(keyroll_file_t *kf)
428 {
429 bytearray_output_stream_init_ex(&kf->baos, kf->data, kf->data_size, BYTEARRAY_DYNAMIC);
430 }
431
keyroll_file_write(keyroll_file_t * kf,const char * filename,const void * data,size_t data_size)432 void keyroll_file_write(keyroll_file_t *kf, const char* filename, const void *data, size_t data_size)
433 {
434 size_t filename_len = strlen(filename) + 1; // +1 for the terminator
435 output_stream_write_u8(&kf->baos, filename_len);
436 output_stream_write(&kf->baos, filename, filename_len);
437
438 output_stream_write_u16(&kf->baos, data_size);
439 output_stream_write(&kf->baos, data, data_size);
440 }
441
keyroll_file_write_stop(keyroll_file_t * kf)442 void keyroll_file_write_stop(keyroll_file_t *kf)
443 {
444 kf->data_size = bytearray_output_stream_size(&kf->baos);
445 kf->data = bytearray_output_stream_detach(&kf->baos);
446 output_stream_close(&kf->baos);
447 }
448
449 static ya_result
input_stream_create_from_base64_text(input_stream * is,const char * text,const char * text_limit)450 input_stream_create_from_base64_text(input_stream* is, const char *text, const char* text_limit)
451 {
452 ya_result ret;
453 output_stream baos;
454 char tmp[128];
455 u8 decoded[128];
456
457 bytearray_output_stream_init(&baos, NULL, 0);
458
459 for(;;)
460 {
461 int i;
462 for(i = 0; (i < (int)sizeof(tmp)) && (text < text_limit); ++text)
463 {
464 char c = *text;
465
466 if(base64_character_set_contains(c))
467 {
468 tmp[i++] = c;
469 }
470 }
471
472 if(i == 0)
473 {
474 break;
475 }
476
477 ya_result n = base64_decode(tmp, i, decoded);
478
479 if(FAIL(n))
480 {
481 ret = n;
482 output_stream_close(&baos);
483 return ret;
484 }
485
486 output_stream_write(&baos, decoded, n);
487 }
488
489 bytearray_input_stream_init(is, bytearray_output_stream_buffer(&baos), bytearray_output_stream_size(&baos), TRUE);
490 bytearray_output_stream_detach(&baos);
491 ret = bytearray_input_stream_size(is);
492
493 return ret;
494 }
495
496 static ya_result
keyroll_parse_record(parser_s * parser,dns_resource_record ** rrp)497 keyroll_parse_record(parser_s *parser, dns_resource_record **rrp)
498 {
499 ya_result ret;
500
501 s32 rttl;
502 s32 rdata_size = RECORD_SIZE_MAX;
503 u16 rtype;
504 u8 fqdn[MAX_DOMAIN_LENGTH];
505 u8 rdata[RECORD_SIZE_MAX]; // enough for a 8192 bits key
506
507 // parse the domain (must match)
508
509 if(FAIL(ret = parser_copy_next_fqdn(parser, fqdn)))
510 {
511 return ret;
512 }
513
514 // parse the TTL
515
516 if(FAIL(ret = parser_copy_next_ttl(parser, &rttl)))
517 {
518 return ret;
519 }
520
521 // parse the type (should be DNSKEY or RRSIG)
522
523 if(FAIL(ret = parser_copy_next_type(parser, &rtype)))
524 {
525 return ret;
526 }
527
528 if((rtype == TYPE_DNSKEY) || (rtype == TYPE_RRSIG))
529 {
530 // parse the rdata using zone_reader_text_copy_rdata
531
532 if(FAIL(ret = parser_concat_next_tokens(parser)))
533 {
534 return ret;
535 }
536
537 char *rdata_text = (char*)parser_text(parser);
538 int rdata_text_size = parser_text_length(parser);
539
540 ret = zone_reader_text_len_copy_rdata(rdata_text, rdata_text_size, rtype, rdata, rdata_size, fqdn);
541
542 if(ISOK(ret))
543 {
544 rdata_size = ret;
545 if(rtype == TYPE_RRSIG)
546 {
547 if(rrsig_get_type_covered_from_rdata(rdata, rdata_size) != TYPE_DNSKEY)
548 {
549 return INVALID_STATE_ERROR;
550 }
551 }
552
553 *rrp = dns_resource_record_new_instance();
554 dns_resource_record_init_record(*rrp, fqdn, rtype, CLASS_IN, rttl, rdata_size, rdata);
555 }
556 }
557 else
558 {
559 // error
560 ret = KEYROLL_EXPECTED_DNSKEY_OR_RRSIG;
561 }
562
563 return ret;
564 }
565
566 static ya_result
keyroll_plan_step_load(keyroll_t * keyroll,const char * file)567 keyroll_plan_step_load(keyroll_t *keyroll, const char *file)
568 {
569 keyroll_step_t *step = NULL;
570 input_stream fis;
571 s64 epochus;
572 ya_result ret;
573
574 // keyroll file
575
576 // load file
577
578 // read the whole file in memory
579 // read it line by line
580
581 struct parser_s parser;
582
583 char full_path[PATH_MAX];
584
585 if(FAIL(ret = parser_init(&parser,
586 "", // by 2
587 "", // by 2
588 "", // by 1
589 " \r\t", // by 1
590 "\\"))) // by 1
591 {
592 return ret;
593 }
594
595 log_debug("parsing '%s'", file);
596
597 snformat(full_path, sizeof(full_path), "%s/%s", keyroll->plan_path, file);
598
599 ret = file_input_stream_open(&fis, full_path);
600
601 if(ISOK(ret))
602 {
603 if(ISOK(ret = parser_push_stream(&parser, &fis)))
604 {
605 // start to parse
606 // it's always:
607 // command words
608 // parameters
609
610 dnskey_keyring *kr = dnskey_keyring_new();
611
612 char command[32];
613
614 for(;;)
615 {
616 if(FAIL(ret = parser_copy_next_word(&parser, command, sizeof(command))))
617 {
618 if(step != NULL)
619 {
620 if(ret == PARSER_REACHED_END_OF_LINE)
621 {
622 continue;
623 }
624
625 if(ret == PARSER_REACHED_END_OF_FILE)
626 {
627 ret = SUCCESS;
628 }
629 }
630
631 break;
632 }
633
634 int n = ret;
635
636 if(step == NULL)
637 {
638 if((n == 7) && (memcmp(command, "epochus", 7) == 0))
639 {
640 char epochus_buffer[24];
641
642 if(FAIL(ret = parser_copy_next_word(&parser, epochus_buffer, sizeof(epochus_buffer))))
643 {
644 break;
645 }
646
647 n = ret;
648
649 if(FAIL(ret = parse_u64_check_range_len_base10(epochus_buffer, n, (u64*)&epochus, 0, MAX_S64)))
650 {
651 break;
652 }
653
654 step = keyroll_get_step(keyroll, epochus);
655 }
656 else
657 {
658 log_err("parsing '%s': the first keyword of a step should be 'epochus', not '%s'", file, command);
659 ret = PARSESTRING_ERROR;
660
661 break;
662 }
663 }
664 else // step != NULL
665 {
666 if((n == 6) && (memcmp(command, "dateus", 6) == 0))
667 {
668 // human readable, epochus check
669
670 char date_buffer[16];
671 char time_buffer[20];
672
673 if(FAIL(ret = parser_copy_next_word(&parser, date_buffer, sizeof(date_buffer))))
674 {
675 break;
676 }
677
678 if(FAIL(ret = parser_copy_next_word(&parser, time_buffer, sizeof(time_buffer))))
679 {
680 break;
681 }
682
683 char datetime_check[64];
684 char datetime_check2[64];
685 snformat(datetime_check, sizeof(datetime_check), "%llU", step->epochus);
686 strcpy(datetime_check2, date_buffer);
687 strcat(datetime_check2, " ");
688 strcat(datetime_check2, time_buffer);
689
690 if(strcmp(datetime_check, datetime_check2) != 0)
691 {
692 flushout();
693 osformatln(termerr, "'%s' does not match '%s' (%lli)", datetime_check, datetime_check2, step->epochus);
694 flusherr();
695 log_err("'%s' does not match '%s' (%lli)", datetime_check, datetime_check2, step->epochus);
696 ret = INVALID_STATE_ERROR;
697 break;
698 }
699 }
700 else if((n == 7) && (memcmp(command, "actions", 7) == 0))
701 {
702 // human readable, implies some of the commands that will follow
703
704 for(;;)
705 {
706 ret = parser_next_word(&parser);
707
708 if(FAIL(ret))
709 {
710 break;
711 }
712 }
713
714 if(ret == PARSER_REACHED_END_OF_LINE)
715 {
716 continue;
717 }
718 else
719 {
720 break;
721 }
722 }
723 else if((n == 5) && (memcmp(command, "debug", 5) == 0))
724 {
725 // human readable, implies some of the commands that will follow
726
727 for(;;)
728 {
729 ret = parser_next_word(&parser);
730
731 if(FAIL(ret))
732 {
733 break;
734 }
735 }
736
737 if(ret == PARSER_REACHED_END_OF_LINE)
738 {
739 continue;
740 }
741 else
742 {
743 break;
744 }
745 }
746 else if((n == 7) && (memcmp(command, "version", 7) == 0))
747 {
748 // version, ignored
749
750 for(;;)
751 {
752 ret = parser_next_word(&parser);
753
754 if(FAIL(ret))
755 {
756 break;
757 }
758 }
759
760 if(ret == PARSER_REACHED_END_OF_LINE)
761 {
762 continue;
763 }
764 else
765 {
766 break;
767 }
768 }
769 else if( ((n == 3) && (memcmp(command, "add", 3) == 0)) || ((n == 3) && (memcmp(command, "del", 3) == 0)) )
770 {
771 // filename base64 of a file
772 char file_name[MAX_DOMAIN_TEXT_LENGTH + 2];
773 char domain_name[MAX_DOMAIN_TEXT_LENGTH + 2];
774
775 if(FAIL(ret = parser_copy_next_word(&parser, file_name, sizeof(file_name))))
776 {
777 break;
778 }
779
780 if(ret < 16) // name has to be a bare minimal size 1 + 1 + 4 + 6 + (4,8) = (15,19)
781 {
782 ret = PARSESTRING_ERROR;
783 break;
784 }
785
786 if(step == NULL)
787 {
788 return INVALID_STATE_ERROR;
789 }
790
791 n = ret;
792
793 // line += n;
794
795 // everything else is the base64 encoding of a file
796
797 u32 algorithm;
798 u32 tag;
799
800 if(sscanf(file_name, "K%255[^+]+%03u+%05u.", domain_name, &algorithm, &tag) != 3)
801 {
802 ret = PARSESTRING_ERROR;
803 break;
804 }
805
806 bool is_public = (memcmp(&file_name[n - 4], ".key", 4) == 0);
807 bool is_private = !is_public && (memcmp(&file_name[n - 8], ".private", 8) == 0);
808
809 if(command[0] == 'd')
810 {
811 // delete
812
813 ptr_vector_append(&step->file_del, strdup(file_name));
814
815 if(FAIL(ret = parser_concat_next_tokens_nospace(&parser)))
816 {
817 break;
818 }
819 }
820 else
821 {
822 // add
823 if(FAIL(ret = parser_concat_next_tokens_nospace(&parser)))
824 {
825 break;
826 }
827
828 input_stream bais;
829
830 if(FAIL(ret = input_stream_create_from_base64_text(&bais, parser_text(&parser), &parser_text(&parser)[parser_text_length(&parser)])))
831 {
832 break;
833 }
834
835 if(is_public)
836 {
837 dnssec_key *key;
838 if(ISOK(ret = dnskey_new_public_key_from_stream(&bais, &key)))
839 {
840 dnskey_keyring_add(kr, key);
841 dnskey_release(key);
842 }
843 else
844 {
845 log_err("failed to get new public key from stream: %r", ret);
846 }
847
848 // keep a copy of the added file
849
850 ptr_node *node = ptr_set_insert(&step->file_add, file_name);
851 if(node->value == NULL)
852 {
853 node->key = strdup(file_name);
854 input_stream *is;
855 ZALLOC_OBJECT_OR_DIE(is, input_stream, GENERIC_TAG);
856 input_stream_create_from_base64_text(is, parser_text(&parser), &parser_text(&parser)[parser_text_length(&parser)]);
857 node->value = is;
858 }
859 else
860 {
861 // already exists
862 ret = INVALID_STATE_ERROR;
863 break;
864 }
865
866 //
867 }
868 else if(is_private)
869 {
870 dnssec_key *key = dnskey_keyring_acquire(kr, algorithm, tag, keyroll->domain);
871
872 ret = dnskey_add_private_key_from_stream(&bais, key, NULL, dnskey_get_algorithm(key));
873
874 log_debug("adding key to keystore: %i, %i, create=%llU publish=%llU activate=%llU deactivate=%llU unpublish=%llU",
875 dnskey_get_algorithm(key),
876 ntohs(dnskey_get_flags(key)),
877 ONE_SECOND_US * dnskey_get_created_epoch(key),
878 ONE_SECOND_US * dnskey_get_publish_epoch(key),
879 ONE_SECOND_US * dnskey_get_activate_epoch(key),
880 ONE_SECOND_US * dnskey_get_inactive_epoch(key),
881 ONE_SECOND_US * dnskey_get_delete_epoch(key));
882 #if 0
883 if(dnskey_get_publish_epoch(key) == 0)
884 {
885 keyroll_set_timing_steps(keyroll, key, FALSE);
886
887 log_debug("------ key to keystore: %i, %i, create=%llU publish=%llU activate=%llU deactivate=%llU unpublish=%llU",
888 dnskey_get_algorithm(key),
889 ntohs(dnskey_get_flags(key)),
890 ONE_SECOND_US * dnskey_get_created_epoch(key),
891 ONE_SECOND_US * dnskey_get_publish_epoch(key),
892 ONE_SECOND_US * dnskey_get_activate_epoch(key),
893 ONE_SECOND_US * dnskey_get_inactive_epoch(key),
894 ONE_SECOND_US * dnskey_get_delete_epoch(key));
895 }
896 #endif
897 dnssec_keystore_add_key(key);
898 /*
899 if(command[0] == 'd')
900 {
901 ptr_vector_append(&step->dnskey_del, key);
902 dnskey_acquire(key);
903 }
904 else
905 {
906 ptr_vector_append(&step->dnskey_add, key);
907 dnskey_acquire(key);
908 }
909 */
910 step->dirty = FALSE;
911
912 if(is_public || (is_private && (dnskey_get_flags(key) != DNSKEY_FLAGS_KSK)))
913 {
914 // keep a copy of the added file
915
916 ptr_node *node = ptr_set_insert(&step->file_add, file_name);
917 if(node->value == NULL)
918 {
919 char *name = strdup(file_name);
920 node->key = name;
921
922 input_stream *is;
923 ZALLOC_OBJECT_OR_DIE(is, input_stream, GENERIC_TAG);
924 input_stream_create_from_base64_text(is, parser_text(&parser), &parser_text(&parser)[parser_text_length(&parser)]);
925
926 node->value = is;
927 }
928 else
929 {
930 ret = INVALID_STATE_ERROR;
931 break;
932 }
933
934 //
935 }
936
937 dnskey_release(key);
938 }
939 else
940 {
941 ret = PARSESTRING_ERROR;
942 }
943 }
944
945 if(FAIL(ret))
946 {
947 break;
948 }
949 }
950 else if((n == 6) && (memcmp(command, "update", 6) == 0))
951 {
952 // the list of nsupdate commands (add and delete)
953
954 char subcommand[16];
955
956 if(FAIL(ret = parser_copy_next_word(&parser, subcommand, sizeof(subcommand))))
957 {
958 break;
959 }
960
961 n = ret;
962
963 int subcommand_type;
964
965 if((n == 3) && (memcmp(subcommand, "add", 3) == 0))
966 {
967 subcommand_type = UPDATE_SUBCOMMAND_ADD;
968 }
969 else if((n == 6) && (memcmp(subcommand, "delete", 6) == 0))
970 {
971 subcommand_type = UPDATE_SUBCOMMAND_DELETE;
972 }
973 else
974 {
975 ret = KEYROLL_UPDATE_SUBCOMMAND_ERROR;
976 break;
977 }
978
979 // parse the record
980
981 dns_resource_record *rr = NULL;
982
983 if(ISOK(ret = keyroll_parse_record(&parser, &rr)))
984 {
985 log_debug("update add %{dnszrr}", rr);
986
987 if(subcommand_type == UPDATE_SUBCOMMAND_ADD)
988 {
989 switch(rr->tctr.qtype) // scan-build false positive (ISOK => rr not NULL)
990 {
991 case TYPE_RRSIG:
992 {
993 u16 tag = rrsig_get_key_tag_from_rdata(rr->rdata, rr->rdata_size);
994 //u8 algorithm = rrsig_get_algorithm_from_rdata(rr->rdata, rr->rdata_size);
995 dnssec_key *key = dnssec_keystore_acquire_key_from_fqdn_with_tag(keyroll->domain, tag);
996 if(key != NULL)
997 {
998 if(dnskey_get_flags(key) == DNSKEY_FLAGS_KSK)
999 {
1000 u32 valid_from = rrsig_get_valid_from_from_rdata(rr->rdata, rr->rdata_size);
1001 u32 valid_until = rrsig_get_valid_until_from_rdata(rr->rdata, rr->rdata_size);
1002 if(!dnskey_has_explicit_activate(key))
1003 {
1004 dnskey_set_activate_epoch(key, valid_from + RRSIG_ANTEDATING * 2);
1005 }
1006 if(!dnskey_has_explicit_deactivate(key))
1007 {
1008 dnskey_set_inactive_epoch(key, valid_until);
1009 }
1010 }
1011 ptr_vector_append(&step->rrsig_add, rr);
1012 dnskey_release(key);
1013 }
1014 else
1015 {
1016 ptr_vector_append(&step->rrsig_add, rr);
1017 }
1018 break;
1019 }
1020 case TYPE_DNSKEY:
1021 {
1022 // if the key is a KZK, load its private key if it's available
1023
1024 dnssec_key *key = NULL;
1025
1026 if(keyroll->generation_mode && (DNSKEY_FLAGS_FROM_RDATA(rr->rdata) == DNSKEY_FLAGS_KSK))
1027 {
1028 ret = dnssec_keystore_load_private_key_from_rdata(rr->rdata, rr->rdata_size, rr->name, &key);
1029 if(ISOK(ret))
1030 {
1031 if(!dnskey_is_private(key))
1032 {
1033 log_err("parsing '%s': private file for key signing key K%{dnsname}+%03i+%05i is missing", file,
1034 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key));
1035 ret = ERROR;
1036 }
1037 }
1038 }
1039 else
1040 {
1041 ret = dnssec_keystore_load_public_key_from_rdata(rr->rdata, rr->rdata_size, rr->name, &key);
1042 }
1043
1044 if(FAIL(ret))
1045 {
1046 if(key != NULL)
1047 {
1048 dnskey_release(key);
1049 }
1050
1051 rdata_desc rdatadesc = {TYPE_DNSKEY, rr->rdata_size, rr->rdata};
1052 flushout();
1053 osformatln(termerr, "parsing '%s': unable to load key: %{dnsname} IN %{typerdatadesc}: %r", file, rr->name, &rdatadesc, ret);
1054 flusherr();
1055 log_err("parsing '%s': unable to load key: %{dnsname} IN %{typerdatadesc}: %r", file, rr->name, &rdatadesc, ret);
1056 return ret;
1057 }
1058
1059 // ignore duplicates
1060
1061 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_add); ++i)
1062 {
1063 dnssec_key *keyi = (dnssec_key*)ptr_vector_get(&step->dnskey_add, i);
1064 if(dnskey_equals(keyi, key))
1065 {
1066 dnskey_release(key);
1067 key = NULL;
1068 break;
1069 }
1070 }
1071
1072 if(key != NULL)
1073 {
1074 if(dnskey_get_publish_epoch(key) == 0)
1075 {
1076 dnskey_set_publish_epoch(key, step->epochus / ONE_SECOND_US);
1077 }
1078
1079 ptr_vector_append(&step->dnskey_add, key);
1080 }
1081
1082 dns_resource_record_free(rr);
1083 break;
1084 }
1085 default:
1086 {
1087 log_warn("parsing '%s': unexpected add record type: %{dnszrr}", file, rr);
1088
1089 dns_resource_record_free(rr);
1090 break;
1091 }
1092 }
1093 }
1094 else // UPDATE_SUBCOMMAND_DELETE
1095 {
1096 switch(rr->tctr.qtype) // scan-build false positive (ISOK => rr not NULL)
1097 {
1098 case TYPE_DNSKEY:
1099 {
1100 // if the key is a KZK, load its private key if it's available
1101
1102
1103 dnssec_key *key = NULL;
1104
1105 if(keyroll->generation_mode && (DNSKEY_FLAGS_FROM_RDATA(rr->rdata) == DNSKEY_FLAGS_KSK))
1106 {
1107 ret = dnssec_keystore_load_private_key_from_rdata(rr->rdata, rr->rdata_size, rr->name, &key);
1108
1109 if(ISOK(ret))
1110 {
1111 if(!dnskey_is_private(key))
1112 {
1113 log_err("parsing '%s': private file for key signing key K%{dnsname}+%03i+%05i is missing", file,
1114 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key));
1115 ret = ERROR;
1116 }
1117 }
1118 }
1119 else
1120 {
1121 ret = dnssec_keystore_load_public_key_from_rdata(rr->rdata, rr->rdata_size, rr->name, &key);
1122 }
1123
1124 if(FAIL(ret))
1125 {
1126 rdata_desc rdatadesc = {TYPE_DNSKEY, rr->rdata_size, rr->rdata};
1127 flushout();
1128 osformatln(termerr, "parsing '%s': unable to load key: %{dnsname} IN %{typerdatadesc}: %r", file, rr->name, &rdatadesc, ret);
1129 flusherr();
1130 log_err("parsing '%s': unable to load key: %{dnsname} IN %{typerdatadesc}: %r", file, rr->name, &rdatadesc, ret);
1131 return ret;
1132 }
1133
1134 // ignore duplicates
1135
1136 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
1137 {
1138 dnssec_key *keyi = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
1139 if(dnskey_equals(keyi, key))
1140 {
1141 dnskey_release(key);
1142 key = NULL;
1143 break;
1144 }
1145 }
1146
1147 if(key != NULL)
1148 {
1149 if(!dnskey_has_explicit_delete(key))
1150 {
1151 dnskey_set_delete_epoch(key, step->epochus / ONE_SECOND_US);
1152 }
1153
1154 ptr_vector_append(&step->dnskey_del, key);
1155 }
1156
1157 dns_resource_record_free(rr);
1158 break;
1159 }
1160 default:
1161 {
1162 log_warn("parsing '%s': unexpected del record type: %{dnszrr}", file, rr);
1163
1164 dns_resource_record_free(rr);
1165 break;
1166 }
1167 }
1168 }
1169 }
1170 else
1171 {
1172 // error
1173 ret = ERROR;
1174 break;
1175 }
1176 }
1177 else if((n == 6) && (memcmp(command, "expect", 6) == 0))
1178 {
1179 // if the master is queried after this step,
1180 // these are the records that should be returned in the answer
1181
1182 // parse record
1183
1184 dns_resource_record *rr = NULL;
1185
1186 if(ISOK(ret = keyroll_parse_record(&parser, &rr)))
1187 {
1188 ptr_vector_append(&step->expect, rr);
1189 log_debug("expect %{dnszrr}", rr);
1190 }
1191 else
1192 {
1193 // error
1194 ret = ERROR;
1195 break;
1196 }
1197 }
1198 else if((n == 9) && (memcmp(command, "endresult", 9) == 0))
1199 {
1200 // if the master is queried after this step,
1201 // these are the records that should be returned in the answer
1202
1203 // parse record
1204
1205 dns_resource_record *rr = NULL;
1206
1207 if(ISOK(ret = keyroll_parse_record(&parser, &rr)))
1208 {
1209 ptr_vector_append(&step->endresult, rr);
1210 log_debug("expect %{dnszrr}", rr);
1211 }
1212 else
1213 {
1214 // error
1215 ret = ERROR;
1216 break;
1217 }
1218 }
1219 else
1220 {
1221 log_err("parsing '%s': unexpected keyword '%s'", file, command);
1222 ret = PARSESTRING_ERROR;
1223 break;
1224 }
1225 } // endif step != NULL
1226
1227 ret = parser_expect_eol(&parser);
1228
1229 if(FAIL(ret))
1230 {
1231 break;
1232 }
1233 }
1234
1235 parser_pop_stream(&parser);
1236 }
1237 else
1238 {
1239 log_err("parsing '%s': could not push stream of file '%s'", file, full_path);
1240 }
1241
1242 input_stream_close(&fis);
1243
1244 if(ISOK(ret))
1245 {
1246 if(step != NULL)
1247 {
1248 ptr_vector_qsort(&step->expect, keyroll_dns_resource_record_ptr_vector_qsort_callback);
1249 ptr_vector_qsort(&step->endresult, keyroll_dns_resource_record_ptr_vector_qsort_callback);
1250 }
1251 else
1252 {
1253 ret = INVALID_STATE_ERROR;
1254 }
1255 }
1256 else
1257 {
1258 log_err("parsing '%s': keyroll_plan_step_load: failure: %r", file, ret);
1259 }
1260 }
1261 else
1262 {
1263 log_err("parsing '%s': could not open stream for file '%s'", file, full_path);
1264 }
1265
1266 parser_finalize(&parser);
1267
1268 return ret;
1269 }
1270
1271 static ya_result
keyroll_purge_step_readdir_forall_callback(const char * basedir,const char * file,u8 filetype,void * args)1272 keyroll_purge_step_readdir_forall_callback(const char *basedir, const char* file, u8 filetype, void *args)
1273 {
1274 if(filetype == DT_REG)
1275 {
1276 const char *domain = (char*)args;
1277 size_t domain_len = strlen(domain);
1278 size_t name_len = strlen(file);
1279 if(name_len > domain_len)
1280 {
1281 if(memcmp(&file[name_len - domain_len], domain, domain_len) == 0)
1282 {
1283 if(unlink_ex(basedir, file) < 0)
1284 {
1285 ya_result ret = ERRNO_ERROR;
1286 flushout();
1287 osformatln(termerr, "failed to delete '%s': %r", file, ret);
1288 log_err("failed to delete '%s': %r", file, ret);
1289 flusherr();
1290 return ret;
1291 }
1292 }
1293 }
1294 }
1295
1296 return READDIR_CALLBACK_CONTINUE;
1297 }
1298
1299 static ya_result
keyroll_purge_key_readdir_forall_callback(const char * basedir,const char * file,u8 filetype,void * args)1300 keyroll_purge_key_readdir_forall_callback(const char *basedir, const char* file, u8 filetype, void *args)
1301 {
1302 (void)args;
1303 if(filetype == DT_REG)
1304 {
1305 size_t name_len = strlen(file);
1306 if((name_len > 8) && (memcmp(&file[name_len - 8], ".private", 8) == 0))
1307 {
1308 if(unlink_ex(basedir, file) < 0)
1309 {
1310 ya_result ret = ERRNO_ERROR;
1311 flushout();
1312 osformatln(termerr, "failed to delete '%s': %r", file, ret);
1313 flusherr();
1314 log_err("failed to delete '%s': %r", file, ret);
1315 return ret;
1316 }
1317 }
1318 else if((name_len > 4) && (memcmp(&file[name_len - 4], ".key", 4) == 0))
1319 {
1320 if(unlink_ex(basedir, file) < 0)
1321 {
1322 ya_result ret = ERRNO_ERROR;
1323 flushout();
1324 osformatln(termerr, "failed to delete '%s': %r", file, ret);
1325 flusherr();
1326 log_err("failed to delete '%s': %r", file, ret);
1327 return ret;
1328 }
1329 }
1330
1331 }
1332
1333 return READDIR_CALLBACK_CONTINUE;
1334 }
1335
1336 ya_result
keyroll_plan_purge(keyroll_t * keyroll)1337 keyroll_plan_purge(keyroll_t *keyroll)
1338 {
1339 ya_result ret;
1340
1341 char domain[MAX_DOMAIN_TEXT_LENGTH];
1342
1343 dnsname_to_cstr(domain, keyroll->domain);
1344
1345 if(ISOK(ret = readdir_forall(keyroll->plan_path, keyroll_purge_step_readdir_forall_callback, domain)))
1346 {
1347 ret = readdir_forall(keyroll->private_keys_path, keyroll_purge_key_readdir_forall_callback, NULL);
1348 }
1349 return ret;
1350 }
1351
1352 static ya_result
keyroll_plan_load_readdir_forall_callback(const char * basedir,const char * file,u8 filetype,void * args)1353 keyroll_plan_load_readdir_forall_callback(const char *basedir, const char *file, u8 filetype, void *args)
1354 {
1355 (void)basedir;
1356 (void)args;
1357 s64 epochus;
1358
1359 u32 year, month, day;
1360 u32 hours, minutes, seconds;
1361 u32 microseconds;
1362
1363 char fqdn[256];
1364
1365 #ifndef WIN32
1366 if(filetype == DT_CHR)
1367 {
1368 return READDIR_CALLBACK_CONTINUE;
1369 }
1370 #endif
1371
1372 if(sscanf(file, "%04u-%02u-%02u-%02u:%02u:%02u.%06uZ_%016lli_%255s.keyroll",
1373 &year, &month, &day,
1374 &hours, &minutes, &seconds,
1375 µseconds,
1376 &epochus,
1377 fqdn) == 9)
1378 {
1379 char date_check[64];
1380 snformat(date_check, sizeof(date_check), "%llU", epochus);
1381 size_t date_check_len = strlen(date_check);
1382 date_check[10] = '-';
1383 if(memcmp(file, date_check, date_check_len) == 0)
1384 {
1385 ptr_vector *files = (ptr_vector*)args;
1386 ptr_vector_append(files, strdup(file));
1387 }
1388 else
1389 {
1390 formatln("ERROR: date for %lli should start '%s' but its '%s'", epochus, date_check, file);
1391 flushout();
1392 return INVALID_STATE_ERROR;
1393 }
1394 }
1395
1396 return SUCCESS;
1397 }
1398
keyroll_plan_load_ptr_vector_qsort_callback(const void * a,const void * b)1399 static int keyroll_plan_load_ptr_vector_qsort_callback(const void *a, const void *b)
1400 {
1401 int ret = strcmp((char*)a, (char*)b);
1402 return ret;
1403 }
1404
1405 /**
1406 * Loads a plan from disk. (all the steps)
1407 * Loads KSK private keys if they are available.
1408 */
1409
1410 ya_result
keyroll_plan_load(keyroll_t * keyroll)1411 keyroll_plan_load(keyroll_t *keyroll)
1412 {
1413 // reload all private keys (KSK in this case)
1414
1415 dnssec_keystore_reload_domain(keyroll->domain);
1416
1417 ptr_vector files;
1418 ptr_vector_init_ex(&files, 1024);
1419 ya_result ret = readdir_forall(keyroll->plan_path, keyroll_plan_load_readdir_forall_callback, &files);
1420 if(ISOK(ret))
1421 {
1422 ptr_vector_qsort(&files, keyroll_plan_load_ptr_vector_qsort_callback);
1423
1424 for(int i = 0; i <= ptr_vector_last_index(&files); ++i)
1425 {
1426 char *file = (char*)ptr_vector_get(&files, i);
1427
1428 if(FAIL(ret = keyroll_plan_step_load(keyroll, file)))
1429 {
1430 log_err("failed to load '%s' : %r", file, ret);
1431 break;
1432 }
1433 }
1434 }
1435 for(int i = 0; i <= ptr_vector_last_index(&files); ++i)
1436 {
1437 char *file = (char*)ptr_vector_get(&files, i);
1438 free(file);
1439 }
1440 ptr_vector_destroy(&files);
1441 return ret;
1442 }
1443
keyroll_step_new_instance()1444 keyroll_step_t* keyroll_step_new_instance()
1445 {
1446 keyroll_step_t *step;
1447 ZALLOC_OBJECT_OR_DIE(step, keyroll_step_t, GENERIC_TAG);
1448 memset(step, 0 ,sizeof(keyroll_step_t));
1449 step->keyroll = NULL;
1450 step->epochus = 0;
1451 ptr_vector_init_empty(&step->dnskey_del);
1452 ptr_vector_init_empty(&step->dnskey_add);
1453 ptr_vector_init_empty(&step->rrsig_add);
1454 ptr_vector_init_empty(&step->expect);
1455 ptr_vector_init_empty(&step->endresult);
1456 ptr_set_init(&step->file_add);
1457 step->file_add.compare = ptr_set_asciizp_node_compare;
1458 ptr_vector_init_empty(&step->file_del);
1459 //u32_set_init(&step->dnskey_set);
1460 step->fingerprint = 0;
1461 step->from_merge = FALSE;
1462 return step;
1463 }
1464
1465 static void
keyroll_step_delete_dnskey_callback(void * key_)1466 keyroll_step_delete_dnskey_callback(void *key_)
1467 {
1468 dnssec_key *key = (dnssec_key*)key_;
1469 dnskey_release(key);
1470 }
1471
1472 static void
keyroll_step_delete_dns_resource_record_callback(void * rr_)1473 keyroll_step_delete_dns_resource_record_callback(void *rr_)
1474 {
1475 dns_resource_record *rr = (dns_resource_record*)rr_;
1476 dns_resource_record_free(rr);
1477 }
1478
1479 static void
keyroll_step_delete_file_add_callback(ptr_node * node)1480 keyroll_step_delete_file_add_callback(ptr_node *node)
1481 {
1482 free(node->key);
1483 input_stream *is = (input_stream*)node->value;
1484 input_stream_close(is);
1485 ZFREE_OBJECT(is);
1486 }
1487
1488 static void
keyroll_step_delete_file_del_callback(void * str_)1489 keyroll_step_delete_file_del_callback(void *str_)
1490 {
1491 free(str_);
1492 }
1493
1494 ya_result
keyroll_step_delete(keyroll_step_t * step)1495 keyroll_step_delete(keyroll_step_t *step)
1496 {
1497 if(step != NULL)
1498 {
1499 ptr_vector_callback_and_destroy(&step->dnskey_del, keyroll_step_delete_dnskey_callback);
1500 ptr_vector_callback_and_destroy(&step->dnskey_add, keyroll_step_delete_dnskey_callback);
1501 ptr_vector_callback_and_destroy(&step->rrsig_add, keyroll_step_delete_dns_resource_record_callback);
1502 ptr_vector_callback_and_destroy(&step->expect, keyroll_step_delete_dns_resource_record_callback);
1503 ptr_vector_callback_and_destroy(&step->endresult, keyroll_step_delete_dns_resource_record_callback);
1504 ptr_set_callback_and_destroy(&step->file_add, keyroll_step_delete_file_add_callback);
1505 ptr_vector_callback_and_destroy(&step->file_del, keyroll_step_delete_file_del_callback);
1506
1507 step->keyroll = NULL;
1508 step->epochus = 0;
1509
1510 ZFREE_OBJECT(step);
1511 }
1512
1513 return SUCCESS;
1514 }
1515
1516
1517 /**
1518 * Returns the step at the given epoch, or create an empty one
1519 */
1520
1521 keyroll_step_t*
keyroll_get_step(keyroll_t * keyroll,s64 epochus)1522 keyroll_get_step(keyroll_t *keyroll, s64 epochus)
1523 {
1524 u64_node* node = u64_set_insert(&keyroll->steps, epochus);
1525 if(node->value != NULL)
1526 {
1527 return (keyroll_step_t*)node->value;
1528 }
1529 else
1530 {
1531 keyroll_step_t *step = keyroll_step_new_instance();
1532
1533 step->keyroll = keyroll;
1534 step->epochus = epochus;
1535 node->value = step;
1536
1537 return step;
1538 }
1539 }
1540
1541 /**
1542 * Merges two consecutive steps.
1543 */
1544
1545 ya_result
keyroll_step_merge(keyroll_step_t * into,keyroll_step_t * step)1546 keyroll_step_merge(keyroll_step_t *into, keyroll_step_t *step)
1547 {
1548 if(into->keyroll == NULL)
1549 {
1550 into->keyroll = step->keyroll;
1551 }
1552 else if(into->keyroll != step->keyroll)
1553 {
1554 return INVALID_STATE_ERROR;
1555 }
1556
1557 if(into->epochus < step->epochus)
1558 {
1559 into->epochus = step->epochus;
1560 }
1561 else
1562 {
1563 return INVALID_STATE_ERROR;
1564 }
1565
1566 into->from_merge = TRUE;
1567
1568 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
1569 {
1570 dnssec_key *keyi = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
1571 bool not_added_anymore = FALSE;
1572
1573 for(int j = 0; j <= ptr_vector_last_index(&into->dnskey_add); ++j)
1574 {
1575 dnssec_key *keyj = (dnssec_key*)ptr_vector_get(&into->dnskey_add, j);
1576
1577 if(dnskey_equals(keyi, keyj))
1578 {
1579 log_info("DNSKEY K%{dnsname}+%03d+%05d not added anymore", dnskey_get_domain(keyj), dnskey_get_algorithm(keyj), dnskey_get_tag_const(keyj));
1580 ptr_vector_end_swap(&into->dnskey_add, j);
1581 ptr_vector_pop(&into->dnskey_add);
1582 dnskey_release(keyj);
1583 not_added_anymore = TRUE;
1584 }
1585 }
1586
1587 if(!not_added_anymore)
1588 {
1589 dnskey_acquire(keyi);
1590 ptr_vector_append(&into->dnskey_del, keyi);
1591 }
1592 }
1593
1594 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_add); ++i)
1595 {
1596 dnssec_key *keyi = (dnssec_key*)ptr_vector_get(&step->dnskey_add, i);
1597 dnskey_acquire(keyi);
1598 ptr_vector_append(&into->dnskey_add, keyi);
1599 log_info("DNSKEY K%{dnsname}+%03d+%05d added", dnskey_get_domain(keyi), dnskey_get_algorithm(keyi), dnskey_get_tag_const(keyi));
1600 }
1601
1602 if((ptr_vector_last_index(&step->dnskey_add) >= 0) || (ptr_vector_last_index(&step->dnskey_del) >= 0))
1603 {
1604 // if any DNSKEY is added/removed, then no current RRSIG is valid
1605
1606 for(int i = 0; i <= ptr_vector_last_index(&into->rrsig_add); ++i)
1607 {
1608 dns_resource_record *rr = (dns_resource_record*)ptr_vector_get(&into->rrsig_add, i);
1609 dns_resource_record_free(rr);
1610 }
1611
1612 ptr_vector_clear(&into->rrsig_add);
1613 }
1614
1615 for(int i = 0; i <= ptr_vector_last_index(&step->rrsig_add); ++i)
1616 {
1617 dns_resource_record *rr = (dns_resource_record*)ptr_vector_get(&step->rrsig_add, i);
1618 dns_resource_record *rr_copy = dns_resource_record_new_instance();
1619 dns_resource_init_from_record(rr_copy, rr);
1620 ptr_vector_append(&into->rrsig_add, rr_copy);
1621 }
1622
1623 for(int i = 0; i <= ptr_vector_last_index(&into->expect); ++i)
1624 {
1625 dns_resource_record *rr = (dns_resource_record*)ptr_vector_get(&into->expect, i);
1626 dns_resource_record_free(rr);
1627 }
1628
1629 ptr_vector_clear(&into->expect);
1630
1631 for(int i = 0; i <= ptr_vector_last_index(&step->expect); ++i)
1632 {
1633 dns_resource_record *rr = (dns_resource_record*)ptr_vector_get(&step->expect, i);
1634 dns_resource_record *rr_copy = dns_resource_record_new_instance();
1635 dns_resource_init_from_record(rr_copy, rr);
1636 ptr_vector_append(&into->expect, rr_copy);
1637 }
1638
1639 ptr_vector_clear(&into->endresult);
1640
1641 for(int i = 0; i <= ptr_vector_last_index(&step->endresult); ++i)
1642 {
1643 dns_resource_record *rr = (dns_resource_record*)ptr_vector_get(&step->endresult, i);
1644 dns_resource_record *rr_copy = dns_resource_record_new_instance();
1645 dns_resource_init_from_record(rr_copy, rr);
1646 ptr_vector_append(&into->endresult, rr_copy);
1647 }
1648
1649 for(int i = 0; i <= ptr_vector_last_index(&step->file_del); ++i)
1650 {
1651 char *filename = (char*)ptr_vector_get(&step->file_del, i);
1652 //bool not_added_anymore = FALSE;
1653
1654 ptr_node *node = ptr_set_find(&into->file_add, filename);
1655 if(node != NULL)
1656 {
1657 log_info("'%s' not added anymore", filename);
1658
1659 char *key = (char*)node->key;
1660 input_stream *is = (input_stream*)node->value; // VS false positive: 'is' cannot be NULL or the node would not exist
1661 input_stream_close(is);
1662 ZFREE_OBJECT(is);
1663 node->value = NULL;
1664 ptr_set_delete(&into->file_add, filename);
1665 free(key);
1666
1667 //not_added_anymore = TRUE;
1668 }
1669
1670 // always delete first, as there can be any kind of obsolete files
1671 //if(!not_added_anymore)
1672 {
1673 ptr_vector_append(&into->file_del, strdup(filename));
1674 }
1675 }
1676
1677 ptr_set_iterator iter;
1678 ptr_set_iterator_init(&step->file_add, &iter);
1679 while(ptr_set_iterator_hasnext(&iter))
1680 {
1681 ptr_node *node = ptr_set_iterator_next_node(&iter);
1682 char *filename = node->key;
1683
1684 ptr_node *into_node = ptr_set_insert(&into->file_add, filename);
1685 if(into_node->value == NULL)
1686 {
1687 log_info("'%s' will be added", filename);
1688
1689 // clone the data
1690 into_node->key = strdup(filename);
1691 into_node->value = bytearray_input_stream_clone((input_stream*)node->value);
1692 }
1693 else
1694 {
1695 log_warn("'%s' is a duplicate file add entry", filename);
1696 }
1697 }
1698
1699 return SUCCESS;
1700 }
1701
1702 /**
1703 * Queries the server for its current state (DNSKEY + RRSIG DNSKEY records)
1704 *
1705 * Appends found dns_resource_record* to the ptr_vector
1706 *
1707 * The ptr_vector is expected to be initialised and empty, or at the very least only filled with
1708 * dns_resource_record*
1709 *
1710 */
1711
1712 ya_result
keyroll_dnskey_state_query(const keyroll_t * keyroll,ptr_vector * current_dnskey_rrsig_rr)1713 keyroll_dnskey_state_query(const keyroll_t *keyroll, ptr_vector *current_dnskey_rrsig_rr)
1714 {
1715 ya_result ret;
1716 message_data *mesg = message_new_instance();
1717 message_make_query_ex(mesg, rand(), keyroll->domain, TYPE_DNSKEY, CLASS_IN, MESSAGE_EDNS0_DNSSEC);
1718
1719 if(ISOK(ret = message_query_tcp_with_timeout(mesg, keyroll->server, KEYROLL_QUERY_TIMEOUT_S)))
1720 {
1721 // extract dnskey + rrsig
1722 if(message_isauthoritative(mesg))
1723 {
1724 packet_unpack_reader_data purd;
1725
1726 packet_reader_init_from_message(&purd, mesg);
1727
1728 //u16 qc = message_get_query_count(mesg);
1729 u16 an = message_get_answer_count(mesg);
1730 u16 ns = message_get_authority_count(mesg);
1731 //u16 ar = message_get_additional_count(mesg);
1732
1733 int total = an;
1734 total += ns;
1735
1736 if(ISOK(ret = packet_reader_skip_query_section(&purd)))
1737 {
1738 for(int i = 0 ; i < total; ++i)
1739 {
1740 dns_resource_record *rr = dns_resource_record_new_instance();
1741
1742 if(FAIL(ret = packet_reader_read_dns_resource_record(&purd, rr)))
1743 {
1744 dns_resource_record_free(rr);
1745 break;
1746 }
1747
1748 if(rr->tctr.qtype == TYPE_DNSKEY)
1749 {
1750 ptr_vector_append(current_dnskey_rrsig_rr, rr);
1751 }
1752 else if((rr->tctr.qtype == TYPE_RRSIG) && (rrsig_get_type_covered_from_rdata(rr->rdata, rr->rdata_size) == TYPE_DNSKEY))
1753 {
1754 ptr_vector_append(current_dnskey_rrsig_rr, rr);
1755 }
1756 }
1757 }
1758
1759 if(ISOK(ret))
1760 {
1761 ptr_vector_qsort(current_dnskey_rrsig_rr, keyroll_dns_resource_record_ptr_vector_qsort_callback);
1762 }
1763 }
1764 else
1765 {
1766 log_err("message_query_tcp_with_timeout(mesg, %{hostaddr}, %i) server is not authoritative", keyroll->server, KEYROLL_QUERY_TIMEOUT_S);
1767 // server is not authoritative
1768 ret = INVALID_STATE_ERROR;
1769 }
1770 }
1771 else
1772 {
1773 log_err("message_query_tcp_with_timeout(mesg, %{hostaddr}, %i) returned %r", keyroll->server, KEYROLL_QUERY_TIMEOUT_S, ret);
1774 }
1775
1776 message_free(mesg);
1777
1778 return ret;
1779 }
1780
1781 /**
1782 * Releases the memory used by dns_resource_record* in the ptr_vector
1783 */
1784
1785 void
keyroll_dnskey_state_destroy(ptr_vector * current_dnskey_rrsig_rr)1786 keyroll_dnskey_state_destroy(ptr_vector *current_dnskey_rrsig_rr)
1787 {
1788 for(int i = 0; i <= ptr_vector_last_index(current_dnskey_rrsig_rr); ++i)
1789 {
1790 dns_resource_record *rr = (dns_resource_record*)ptr_vector_get(current_dnskey_rrsig_rr, i);
1791 dns_resource_record_free(rr);
1792 }
1793 ptr_vector_clear(current_dnskey_rrsig_rr);
1794 //
1795 ptr_vector_destroy(current_dnskey_rrsig_rr);
1796 }
1797
1798 /**
1799 * Compares the expected state at a given step with the state on the server
1800 * (queried with keyroll_dnskey_state_query)
1801 *
1802 * Returns SUCCESS iff it's a match.
1803 */
1804
1805 ya_result
keyroll_step_expects_matched(const keyroll_step_t * step,const ptr_vector * dnskey_rrsig_rr)1806 keyroll_step_expects_matched(const keyroll_step_t *step, const ptr_vector *dnskey_rrsig_rr)
1807 {
1808 // ensure a perfect match between expected records and whatever is in dnskey_rrsig_rr
1809 // both ptr_vector are sorted
1810
1811 if(ptr_vector_last_index(&step->expect) == ptr_vector_last_index(dnskey_rrsig_rr))
1812 {
1813 for(int i = 0; i <= ptr_vector_last_index(dnskey_rrsig_rr); ++i)
1814 {
1815 dns_resource_record *ra = ptr_vector_get(&step->expect, i);
1816 dns_resource_record *rb = ptr_vector_get(dnskey_rrsig_rr, i);
1817
1818 if(dns_resource_record_compare(ra, rb) != 0)
1819 {
1820 return KEYROLL_EXPECTED_IDENTICAL_RECORDS;
1821 }
1822 }
1823
1824 return SUCCESS;
1825 }
1826
1827 return KEYROLL_EXPECTED_IDENTICAL_SIZE_RRSETS;
1828 }
1829
1830 /**
1831 * Compares the end-result state at a given step with the state on the server
1832 * (queried with keyroll_dnskey_state_query)
1833 *
1834 * Returns SUCCESS iff it's a match.
1835 */
1836
1837 ya_result
keyroll_step_endresult_matched(const keyroll_step_t * step,const ptr_vector * dnskey_rrsig_rr)1838 keyroll_step_endresult_matched(const keyroll_step_t *step, const ptr_vector *dnskey_rrsig_rr)
1839 {
1840 // ensure a perfect match between end-result records and whatever is in dnskey_rrsig_rr
1841 // both ptr_vector are sorted
1842
1843 if(ptr_vector_last_index(&step->endresult) == ptr_vector_last_index(dnskey_rrsig_rr))
1844 {
1845 for(int i = 0; i <= ptr_vector_last_index(dnskey_rrsig_rr); ++i)
1846 {
1847 dns_resource_record *ra = ptr_vector_get(&step->endresult, i);
1848 dns_resource_record *rb = ptr_vector_get(dnskey_rrsig_rr, i);
1849
1850 if(dns_resource_record_compare(ra, rb) != 0)
1851 {
1852 return KEYROLL_EXPECTED_IDENTICAL_RECORDS;
1853 }
1854 }
1855
1856 return SUCCESS;
1857 }
1858
1859 return KEYROLL_EXPECTED_IDENTICAL_SIZE_RRSETS;
1860 }
1861
1862 /**
1863 * Plays a step on the server
1864 *
1865 * @param step the step to play
1866 * @param delete_all_dnskey delete all keys on the server.
1867 */
1868
1869 ya_result
keyroll_step_play(const keyroll_step_t * step,bool delete_all_dnskey)1870 keyroll_step_play(const keyroll_step_t *step, bool delete_all_dnskey)
1871 {
1872 char path[PATH_MAX];
1873
1874 // delete the files
1875
1876 for(int i = 0; i <= ptr_vector_last_index(&step->file_del); ++i)
1877 {
1878 const char *name = (char*)ptr_vector_get(&step->file_del, i);
1879
1880 // delete the file from he right directory
1881
1882 log_info("%{dnsname}: deleting file: '%s'", step->keyroll->domain, name);
1883
1884 unlink_ex(step->keyroll->keys_path, name);
1885 }
1886
1887 // copy the files
1888
1889 ya_result ret;
1890 ptr_set_iterator iter;
1891 ptr_set_iterator_init(&step->file_add, &iter);
1892 while(ptr_set_iterator_hasnext(&iter))
1893 {
1894 ptr_node *node = ptr_set_iterator_next_node(&iter);
1895 const char *name = (char*)node->key;
1896
1897 // copy the input stream in the right directory
1898
1899 snformat(path, sizeof(path), "%s/%s", step->keyroll->keys_path, name);
1900
1901 int n = strlen(name);
1902 bool is_private_key_file = (n > 8) && (memcmp(&name[n - 8], ".private", 8) == 0);
1903
1904 log_info("%{dnsname}: creating file: '%s'", step->keyroll->domain, path);
1905
1906 output_stream os;
1907 if(ISOK(ret = file_output_stream_create(&os, path, 0640)))
1908 {
1909 input_stream *is = (input_stream*)node->value;
1910
1911 bytearray_input_stream_reset(is);
1912
1913 if(is_private_key_file)
1914 {
1915
1916 // read the file line by line
1917 // remove Publish and Delete lines
1918
1919 for(;;)
1920 {
1921 ret = input_stream_read_line(is, path, sizeof(path));
1922 if(ISOK(ret))
1923 {
1924 if(ret == 0)
1925 {
1926 break;
1927 }
1928
1929 if(memcmp(path, "Publish:", 8) == 0)
1930 {
1931 continue;
1932 }
1933 else if(memcmp(path, "Delete:", 7) == 0)
1934 {
1935 continue;
1936 }
1937
1938 output_stream_write(&os, path, ret);
1939 }
1940 else
1941 {
1942 log_err("keyroll step failure reading bytes for: '%s'", path);
1943 break;
1944 }
1945 }
1946 }
1947 else
1948 {
1949 for(;;)
1950 {
1951 ret = input_stream_read(is, path, sizeof(path));
1952
1953 if(ISOK(ret))
1954 {
1955 if(ret == 0)
1956 {
1957 break;
1958 }
1959
1960 output_stream_write(&os, path, ret);
1961 }
1962 else
1963 {
1964 log_err("keyroll step failure reading bytes for: '%s'", path);
1965 break;
1966 }
1967 }
1968 }
1969
1970 output_stream_close(&os);
1971
1972 if(FAIL(ret))
1973 {
1974 return ret;
1975 }
1976 }
1977 else
1978 {
1979 log_err("keyroll could not create file '%s'", path);
1980 return ret;
1981 }
1982 }
1983
1984 if((ptr_vector_size(&step->dnskey_del) + ptr_vector_size(&step->dnskey_add) + ptr_vector_size(&step->rrsig_add)) == 0)
1985 {
1986 // nothing to do
1987
1988 return SUCCESS;
1989 }
1990
1991 // build an update packet
1992 // commit update packet
1993 // optionally check the server for an expected match
1994
1995 message_data *mesg = message_new_instance();
1996 message_data *answer = message_new_instance();
1997 struct packet_writer pw;
1998 message_make_dnsupdate_init(mesg, rand(), step->keyroll->domain, CLASS_IN, 65535, &pw);
1999
2000 if(delete_all_dnskey)
2001 {
2002 log_info("%{dnsname}: all previous DNSKEY will be removed", step->keyroll->domain);
2003 message_make_dnsupdate_delete_rrset(mesg, &pw, step->keyroll->domain, TYPE_DNSKEY);
2004 }
2005
2006 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
2007 {
2008 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
2009 message_make_dnsupdate_delete_dnskey(mesg, &pw, key);
2010 }
2011
2012 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_add); ++i)
2013 {
2014 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_add, i);
2015 message_make_dnsupdate_add_dnskey(mesg, &pw, key, DNSKEY_TTL_DEFAULT);
2016 }
2017
2018 for(int i = 0; i <= ptr_vector_last_index(&step->rrsig_add); ++i)
2019 {
2020 dns_resource_record *rrsig = (dns_resource_record*)ptr_vector_get(&step->rrsig_add, i);
2021 message_make_dnsupdate_add_dns_resource_record(mesg, &pw, rrsig);
2022 }
2023
2024 if(ISOK(ret = message_make_dnsupdate_finalize(mesg, &pw)))
2025 {
2026 // message has been properly built
2027
2028 message_log(g_keyroll_logger, LOG_INFO, mesg);
2029
2030 bool dnskey_rrsig_needed = (ptr_vector_last_index(&step->dnskey_del) >= 0) || (ptr_vector_last_index(&step->dnskey_add) >= 0);
2031 bool dnskey_rrsig_added = (ptr_vector_last_index(&step->rrsig_add) >= 0);
2032
2033 if(dnskey_rrsig_needed && !dnskey_rrsig_added)
2034 {
2035 log_err("%s%{dnsname}: internal state error: no DNSKEY RRSIG added while the DNSKEY rrset is being modified", "<INTERVENTION> ", step->keyroll->domain);
2036 dnscore_shutdown();
2037 return INVALID_STATE_ERROR;
2038 }
2039
2040 if(!keyroll_dryrun_mode)
2041 {
2042 ret = STOPPED_BY_APPLICATION_SHUTDOWN;
2043
2044 int loops = 0; // only used to display a message once (tries most errors forever)
2045
2046 u32 apply_verify_try_count = 0;
2047
2048 while(!dnscore_shuttingdown())
2049 {
2050 if(ISOK(ret = message_query_tcp_with_timeout_ex(mesg, step->keyroll->server, answer, KEYROLL_QUERY_TIMEOUT_S)))
2051 {
2052 log_info("%{dnsname}: sent message to %{hostaddr}", step->keyroll->domain, step->keyroll->server);
2053
2054 if(message_get_status(answer) == FP_RCODE_NOERROR)
2055 {
2056 log_info("%{dnsname}: %{hostaddr} server replied it did the update", step->keyroll->domain, step->keyroll->server);
2057
2058 // now let's check if the server said the truth
2059
2060 ptr_vector current_dnskey_rrsig_rr;
2061 ptr_vector_init_ex(¤t_dnskey_rrsig_rr, 32);
2062 if(ISOK(ret = keyroll_dnskey_state_query(step->keyroll, ¤t_dnskey_rrsig_rr)))
2063 {
2064 // current_dnskey_rrsig_rr contains the records currently on the server
2065
2066 ya_result matched_expectations = keyroll_step_endresult_matched(step, ¤t_dnskey_rrsig_rr);
2067
2068 log_info("%{dnsname}: current step (%llU) should result in:", step->keyroll->domain, step->epochus);
2069
2070 for(int i = 0; i <= ptr_vector_last_index(&step->endresult); ++i)
2071 {
2072 log_info("%{dnszrr}", ptr_vector_get(&step->endresult, i));
2073 }
2074
2075 log_info("%{dnsname}: server (%{hostaddr}) update resulted in:", step->keyroll->domain, step->keyroll->server);
2076
2077 for(int i = 0; i <= ptr_vector_last_index(¤t_dnskey_rrsig_rr); ++i)
2078 {
2079 log_info("%{dnszrr}", ptr_vector_get(¤t_dnskey_rrsig_rr, i));
2080 }
2081
2082 if(ISOK(matched_expectations))
2083 {
2084 log_info("%{dnsname}: update was applied successfully", step->keyroll->domain);
2085 }
2086 else
2087 {
2088 ++apply_verify_try_count;
2089
2090 log_err("%{dnsname}: update was not applied successfully (try %i/%i)", step->keyroll->domain, apply_verify_try_count, step->keyroll->update_apply_verify_retries + 1);
2091
2092 // 1 vs 1 => must do
2093 if(apply_verify_try_count <= step->keyroll->update_apply_verify_retries)
2094 {
2095 // ret = EAGAIN; // unused
2096 usleep_ex(ONE_SECOND_US * step->keyroll->update_apply_verify_retries_delay);
2097 continue;
2098 }
2099 else
2100 {
2101 log_err("%{dnsname}: update was not applied successfully, no retry left.", step->keyroll->domain);
2102 ret = KEYROLL_MUST_REINITIALIZE;
2103 }
2104 }
2105 }
2106
2107 keyroll_dnskey_state_destroy(¤t_dnskey_rrsig_rr);
2108
2109 break;
2110 }
2111
2112 log_err("%{dnsname}: %{hostaddr} server replied with an error: %s", step->keyroll->domain, step->keyroll->server, dns_message_rcode_get_name(message_get_status(answer)));
2113
2114 ret = MAKE_DNSMSG_ERROR(message_get_status(answer));
2115 break;
2116 }
2117
2118 if(!((ret == MAKE_ERRNO_ERROR(ETIMEDOUT)) || (ret == MAKE_ERRNO_ERROR(EAGAIN) || (ret == UNEXPECTED_EOF))))
2119 {
2120 log_notice("%{dnsname}: sending message to %{hostaddr} failed: %r", step->keyroll->domain, step->keyroll->server, ret);
2121 break;
2122 }
2123
2124 if(!dnscore_shuttingdown())
2125 {
2126 log_warn("%{dnsname}: sending message to %{hostaddr} failed: %r (retrying in one second)", step->keyroll->domain, step->keyroll->server, ret);
2127 sleep(1);
2128
2129 if(++loops == 1) // show the message exactly once
2130 {
2131 if(ret != UNABLE_TO_COMPLETE_FULL_READ)
2132 {
2133 message_log(MODULE_MSG_HANDLE, MSG_INFO, mesg);
2134 }
2135 }
2136 }
2137
2138 ret = STOPPED_BY_APPLICATION_SHUTDOWN;
2139 }
2140 }
2141 else
2142 {
2143 log_warn("%{dnsname}: dryrun mode : no update has been sent", step->keyroll->domain);
2144 }
2145 }
2146
2147 message_free(answer);
2148 message_free(mesg);
2149
2150 return ret;
2151 }
2152
2153 /**
2154 * Plays all the steps in a given epoch range.
2155 */
2156
2157 ya_result
keyroll_step_play_range_ex(const keyroll_t * keyroll,s64 seek_from,s64 now,bool delete_all_dnskey,keyroll_step_t ** first_stepp)2158 keyroll_step_play_range_ex(const keyroll_t *keyroll, s64 seek_from , s64 now, bool delete_all_dnskey, keyroll_step_t **first_stepp)
2159 {
2160 if(seek_from > now)
2161 {
2162 log_err("%{dnsname}: play range from the future to the past (%llU to %llU)", keyroll->domain, seek_from, now);
2163 return INVALID_ARGUMENT_ERROR;
2164 }
2165
2166 ya_result ret;
2167
2168 keyroll_step_t *first_step = keyroll_get_next_step_from(keyroll, seek_from);
2169
2170 if(first_step == NULL)
2171 {
2172 log_info("%{dnsname}: play range has no first step", keyroll->domain);
2173 return INVALID_STATE_ERROR;
2174 }
2175
2176 log_info("%{dnsname}: first step epoch is %llU", keyroll->domain, first_step->epochus);
2177
2178 if(first_step->epochus > now)
2179 {
2180 if(first_stepp != NULL)
2181 {
2182 *first_stepp = first_step;
2183 }
2184
2185 log_info("%{dnsname}: play range will not play %llU as its first step as it's after %llU", keyroll->domain, first_step->epochus, now);
2186 return SUCCESS;
2187 }
2188
2189 log_info("%{dnsname}: play range from %llU", keyroll->domain, first_step->epochus);
2190
2191 keyroll_step_t *merge = keyroll_step_new_instance();
2192 // if a merge occurs, it's important to log it in case something goes wrong
2193 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2194 log_info("%{dnsname}: merging step:", keyroll->domain);
2195 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2196 keyroll_step_print(merge);
2197 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2198 log_info("%{dnsname}: with step:", keyroll->domain);
2199 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2200 keyroll_step_print(first_step);
2201 logger_flush();
2202 keyroll_step_merge(merge, first_step);
2203 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2204 log_info("%{dnsname}: resulting in:", keyroll->domain);
2205 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2206 keyroll_step_print(merge);
2207
2208 s64 tick = first_step->epochus;
2209 while(tick < now)
2210 {
2211 keyroll_step_t *next_step = keyroll_get_next_step_from(keyroll, tick + 1);
2212 if((next_step == NULL) || (next_step->epochus > now))
2213 {
2214 break;
2215 }
2216
2217 log_info("%{dnsname}: then with step:", keyroll->domain);
2218 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2219 keyroll_step_print(next_step);
2220 // logger_flush();
2221 keyroll_step_merge(merge, next_step);
2222 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2223 log_info("%{dnsname}: resulting in:", keyroll->domain);
2224 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2225 keyroll_step_print(merge);
2226 tick = next_step->epochus;
2227 }
2228
2229 log_info("%{dnsname}: play range ends up with the step: ", keyroll->domain);
2230 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2231 keyroll_step_print(merge);
2232 log_info("%{dnsname}: -------------------------------------------", keyroll->domain);
2233 logger_flush();
2234
2235 if(FAIL(ret = keyroll_step_play(merge, delete_all_dnskey)))
2236 {
2237 log_err("%{dnsname}: play range step execute failed: %r", keyroll->domain, ret);
2238 }
2239
2240 if(first_stepp != NULL)
2241 {
2242 *first_stepp = merge;
2243 }
2244
2245 return ret;
2246 }
2247
2248 /**
2249 * Plays all the steps in a given epoch range.
2250 */
2251
2252 ya_result
keyroll_step_play_range(const keyroll_t * keyroll,s64 seek_from,s64 now)2253 keyroll_step_play_range(const keyroll_t *keyroll, s64 seek_from , s64 now)
2254 {
2255 ya_result ret;
2256 ret = keyroll_step_play_range_ex(keyroll, seek_from, now, FALSE, NULL);
2257 return ret;
2258 }
2259
2260 /**
2261 * Plays the first step of a plan if it's before a given epoch.
2262 * If the first step is in the future, it's not played.
2263 * Returns the first step in the parameter.
2264 * Returns an error code.
2265 */
2266
2267 ya_result
keyroll_play_first_step(const keyroll_t * keyroll,s64 now,keyroll_step_t ** first_stepp)2268 keyroll_play_first_step(const keyroll_t *keyroll, s64 now, keyroll_step_t **first_stepp)
2269 {
2270 ya_result ret;
2271 ret = keyroll_step_play_range_ex(keyroll, 0 , now, TRUE, first_stepp);
2272 return ret;
2273 }
2274
2275 /**
2276 * Scans the plan for the step matching the given state
2277 *
2278 * Returns the matching step or NULL
2279 */
2280
2281 keyroll_step_t*
keyroll_step_scan_matching_expectations(const keyroll_t * keyroll,ptr_vector * current_dnskey_rrsig_rr)2282 keyroll_step_scan_matching_expectations(const keyroll_t *keyroll, ptr_vector *current_dnskey_rrsig_rr)
2283 {
2284 s64 t = 0;
2285
2286 for(;;)
2287 {
2288 keyroll_step_t *step = keyroll_get_next_step_from(keyroll, t);
2289
2290 if(step == NULL)
2291 {
2292 return NULL;
2293 }
2294
2295 ya_result ret = keyroll_step_expects_matched(step, current_dnskey_rrsig_rr);
2296
2297 if(ret == SUCCESS)
2298 {
2299 return step;
2300 }
2301
2302 t = step->epochus + 1;
2303 }
2304 }
2305
2306 /**
2307 * Returns the step being active at the given epoch or NULL if there is no such step.
2308 * If a step starts at the given epoch, it's the one returned.
2309 */
2310
2311 keyroll_step_t*
keyroll_get_current_step_at(const keyroll_t * keyroll,s64 epochus)2312 keyroll_get_current_step_at(const keyroll_t *keyroll, s64 epochus)
2313 {
2314 u64_node* node = u64_set_find_key_or_prev(&keyroll->steps, epochus);
2315
2316 if(node != NULL)
2317 {
2318 return (keyroll_step_t*)node->value;
2319 }
2320 else
2321 {
2322 return NULL;
2323 }
2324 }
2325
2326 /**
2327 * Returns the next step to be active from the given epoch or NULL if there is no such step.
2328 * If a step starts at the given epoch, it's the one returned.
2329 */
2330
2331 keyroll_step_t*
keyroll_get_next_step_from(const keyroll_t * keyroll,s64 epochus)2332 keyroll_get_next_step_from(const keyroll_t *keyroll, s64 epochus)
2333 {
2334 u64_node* node = u64_set_find_key_or_next(&keyroll->steps, epochus);
2335
2336 if(node != NULL)
2337 {
2338 return (keyroll_step_t*)node->value;
2339 }
2340 else
2341 {
2342 return NULL;
2343 }
2344 }
2345
2346 /**
2347 * Generates a DNSKEY to be published at the given epoch.
2348 * The DNSKEY can be set as a KSK or ZSK using the ksk parameter.
2349 * This function creates steps at the various time fields of the key.
2350 */
2351
2352 ya_result
keyroll_generate_dnskey(keyroll_t * keyroll,s64 publication_epochus,bool ksk)2353 keyroll_generate_dnskey(keyroll_t *keyroll, s64 publication_epochus, bool ksk)
2354 {
2355 dnssec_key *key = NULL;
2356 ya_result ret;
2357 const keyroll_key_parameters_t *kp = ksk?&keyroll->ksk_parameters:&keyroll->zsk_parameters;
2358 s64 *next_deactivationp = ksk?&keyroll->ksk_next_deactivation:&keyroll->zsk_next_deactivation;
2359
2360 char name[MAX_DOMAIN_TEXT_LENGTH];
2361
2362 if(FAIL(ret = dnsname_to_cstr(name, keyroll->domain)))
2363 {
2364 return ret;
2365 }
2366
2367 log_info("%{dnsname}: generating %cSK key to publish at %llU", keyroll->domain, ksk?'K':'Z', publication_epochus);
2368
2369 if(ISOK(ret = dnskey_newinstance(
2370 kp->size,
2371 kp->algorithm,
2372 ksk?(DNSKEY_FLAG_ZONEKEY | DNSKEY_FLAG_KEYSIGNINGKEY):DNSKEY_FLAG_ZONEKEY,
2373 name, &key)))
2374 {
2375 log_info("%{dnsname}: generated %cSK key to publish at %llU", keyroll->domain, ksk?'K':'Z', publication_epochus);
2376 //u16 tag = dnskey_get_tag(key);
2377
2378 keyroll_step_t* publication_step = keyroll_get_step(keyroll, publication_epochus);
2379 publication_step->keyroll_action |= /*KeyrollAction::*/Publish;
2380 ptr_vector_append(&publication_step->dnskey_add, key);
2381 dnskey_acquire(key);
2382 publication_step->dirty = TRUE;
2383 dnskey_set_publish_epoch(key, publication_epochus / ONE_SECOND_US);
2384
2385 s64 activate_epochus = publication_epochus + ONE_SECOND_US * kp->activate_after;
2386 keyroll_step_t *activation_step = keyroll_get_step(keyroll, activate_epochus);
2387 activation_step->keyroll_action |= /*KeyrollAction::*/Activate;
2388 activation_step->dirty = TRUE;
2389 dnskey_set_activate_epoch(key, activate_epochus / ONE_SECOND_US);
2390
2391 s64 deactivate_epochus = publication_epochus + ONE_SECOND_US * kp->deactivate_after;
2392 keyroll_step_t *deactivation_step = keyroll_get_step(keyroll, deactivate_epochus);
2393 deactivation_step->keyroll_action |= /*KeyrollAction::*/Deactivate;
2394 deactivation_step->dirty = TRUE;
2395
2396 s64 unpublish_epochus = publication_epochus + ONE_SECOND_US * kp->delete_after;
2397
2398 time_t deactivate_epoch_margin = keyroll_deactivation_margin(dnskey_get_activate_epoch(key), deactivate_epochus / ONE_SECOND_US, unpublish_epochus / ONE_SECOND_US);
2399 time_t deactivate_epoch = (deactivate_epochus/ ONE_SECOND_US) + deactivate_epoch_margin;
2400
2401 dnskey_set_inactive_epoch(key, deactivate_epoch);
2402
2403 if(*next_deactivationp < deactivation_step->epochus)
2404 {
2405 *next_deactivationp = deactivation_step->epochus;
2406 }
2407
2408 keyroll_step_t *unpublication_step = keyroll_get_step(keyroll, unpublish_epochus);
2409 ptr_vector_append(&unpublication_step->dnskey_del, key);
2410 dnskey_acquire(key);
2411 unpublication_step->keyroll_action |= /*KeyrollAction::*/Unpublish;
2412 unpublication_step->dirty = TRUE;
2413 time_t unpublish_epoch = MAX(unpublish_epochus / ONE_SECOND_US, deactivate_epoch);
2414 dnskey_set_delete_epoch(key, unpublish_epoch);
2415 /*
2416 formatln("created key: tag=%i, algorithm=%i, flags=%i, create=%U publish=%U activate=%U deactivate=%U unpublish=%U",
2417 dnskey_get_tag(key),
2418 dnskey_get_algorithm(key),
2419 ntohs(dnskey_get_flags(key)),
2420 dnskey_get_created_epoch(key),
2421 dnskey_get_publish_epoch(key),
2422 dnskey_get_activate_epoch(key),
2423 dnskey_get_inactive_epoch(key),
2424 dnskey_get_delete_epoch(key));
2425 */
2426 dnskey_release(key); // the original reference
2427 }
2428 else
2429 {
2430 log_info("%{dnsname}: failed to generate %cSK key to publish at %llU: %r", keyroll->domain, ksk?'K':'Z', publication_epochus, ret);
2431 }
2432
2433 return ret;
2434 }
2435
2436 s64
keyroll_set_timing_steps(keyroll_t * keyroll,dnssec_key * key,bool dirty)2437 keyroll_set_timing_steps(keyroll_t *keyroll, dnssec_key *key, bool dirty)
2438 {
2439 s64 publication_epochus = ONE_SECOND_US * dnskey_get_publish_epoch(key);
2440 keyroll_step_t* publication_step = keyroll_get_step(keyroll, publication_epochus);
2441 publication_step->keyroll_action |= /*KeyrollAction::*/Publish;
2442
2443 ptr_vector_append(&publication_step->dnskey_add, key);
2444 dnskey_acquire(key);
2445
2446 publication_step->dirty = dirty;
2447 dnskey_set_publish_epoch(key, publication_epochus / ONE_SECOND_US);
2448
2449 s64 activate_epochus = ONE_SECOND_US * dnskey_get_activate_epoch(key);
2450 keyroll_step_t *activation_step = keyroll_get_step(keyroll, activate_epochus);
2451 activation_step->keyroll_action |= /*KeyrollAction::*/Activate;
2452 activation_step->dirty = dirty;
2453 dnskey_set_activate_epoch(key, activate_epochus / ONE_SECOND_US);
2454
2455 s64 deactivate_epochus = ONE_SECOND_US * dnskey_get_inactive_epoch(key);
2456 keyroll_step_t *deactivation_step = keyroll_get_step(keyroll, deactivate_epochus);
2457 deactivation_step->keyroll_action |= /*KeyrollAction::*/Deactivate;
2458 deactivation_step->dirty = dirty;
2459
2460 s64 unpublish_epochus = ONE_SECOND_US * dnskey_get_delete_epoch(key);
2461
2462 time_t deactivate_epoch_margin = keyroll_deactivation_margin(dnskey_get_activate_epoch(key), deactivate_epochus / ONE_SECOND_US, unpublish_epochus / ONE_SECOND_US);
2463
2464 time_t deactivation_epoch = (deactivate_epochus / ONE_SECOND_US) + deactivate_epoch_margin;
2465 dnskey_set_inactive_epoch(key, deactivation_epoch);
2466
2467 keyroll_step_t *unpublication_step = keyroll_get_step(keyroll, unpublish_epochus);
2468 ptr_vector_append(&unpublication_step->dnskey_del, key);
2469 dnskey_acquire(key);
2470 unpublication_step->keyroll_action |= /*KeyrollAction::*/Unpublish;
2471 unpublication_step->dirty = dirty;
2472 time_t unpublish_epoch = MAX(unpublish_epochus / ONE_SECOND_US, deactivation_epoch);
2473 dnskey_set_delete_epoch(key, unpublish_epoch);
2474
2475 return deactivate_epochus;
2476 }
2477
2478 /**
2479 * Generates a DNSKEY to be published at the given epoch.
2480 * The DNSKEY can be set as a KSK or ZSK using the ksk parameter.
2481 * This functions requires the time fields to be set manually.
2482 * This function creates steps at the various time fields of the key.
2483 */
2484
2485 ya_result
keyroll_generate_dnskey_ex(keyroll_t * keyroll,u32 size,u8 algorithm,s64 creation_epochus,s64 publication_epochus,s64 activate_epochus,s64 deactivate_epochus,s64 unpublish_epochus,bool ksk,dnssec_key ** out_keyp)2486 keyroll_generate_dnskey_ex(keyroll_t *keyroll, u32 size, u8 algorithm,
2487 s64 creation_epochus,
2488 s64 publication_epochus,
2489 s64 activate_epochus,
2490 s64 deactivate_epochus,
2491 s64 unpublish_epochus,
2492 bool ksk,
2493 dnssec_key **out_keyp)
2494 {
2495 dnssec_key *key = NULL;
2496 ya_result ret;
2497
2498 if((keyroll == NULL) || (keyroll->domain == NULL))
2499 {
2500 return INVALID_STATE_ERROR;
2501 }
2502
2503 //formatln("%{dnsname}: generate %s key %llU %llU %llU %llU %llU", keyroll->domain, (ksk?"KSK":"ZSK"), creation_epochus, publication_epochus, activate_epochus, deactivate_epochus,unpublish_epochus);
2504
2505 s64 *next_deactivationp = ksk?&keyroll->ksk_next_deactivation:&keyroll->zsk_next_deactivation;
2506
2507 char name[MAX_DOMAIN_TEXT_LENGTH];
2508
2509 if(FAIL(ret = dnsname_to_cstr(name, keyroll->domain)))
2510 {
2511 return ret;
2512 }
2513
2514 log_info("%{dnsname}: generating %cSK key to publish at %llU", keyroll->domain, ksk?'K':'Z', publication_epochus);
2515
2516 while(!dnscore_shuttingdown()) // while there are tag collisions
2517 {
2518 if(ISOK(ret = dnskey_newinstance(
2519 size,
2520 algorithm,
2521 ksk?(DNSKEY_FLAG_ZONEKEY | DNSKEY_FLAG_KEYSIGNINGKEY):DNSKEY_FLAG_ZONEKEY,
2522 name, &key)))
2523 {
2524 dnssec_key *previous_key_with_same_tag = dnssec_keystore_acquire_key_from_fqdn_with_tag(dnskey_get_domain(key), dnskey_get_tag(key));
2525 if(previous_key_with_same_tag != NULL)
2526 {
2527 log_notice("%{dnsname}: a tag collision happened creating a %cSK key. Discarding and trying again.", keyroll->domain, ksk?'K':'Z');
2528 dnskey_release(previous_key_with_same_tag);
2529 dnskey_release(key);
2530
2531 ret = DNSSEC_ERROR_DUPLICATEKEY; // actually the tag is a duplicate ...
2532 continue;
2533 }
2534
2535 log_info("%{dnsname}: generated %cSK key to publish at %llU", keyroll->domain, ksk?'K':'Z', publication_epochus);
2536 //u16 tag = dnskey_get_tag(key);
2537
2538 dnskey_set_created_epoch(key, creation_epochus / ONE_SECOND_US);
2539
2540 keyroll_step_t* publication_step = keyroll_get_step(keyroll, publication_epochus);
2541 publication_step->keyroll_action |= /*KeyrollAction::*/Publish;
2542 ptr_vector_append(&publication_step->dnskey_add, key);
2543 dnskey_acquire(key);
2544 publication_step->dirty = TRUE;
2545 dnskey_set_publish_epoch(key, publication_epochus / ONE_SECOND_US);
2546
2547 keyroll_step_t *activation_step = keyroll_get_step(keyroll, activate_epochus);
2548 activation_step->keyroll_action |= /*KeyrollAction::*/Activate;
2549 activation_step->dirty = TRUE;
2550 dnskey_set_activate_epoch(key, activate_epochus / ONE_SECOND_US);
2551
2552 time_t deactivate_epoch_margin = keyroll_deactivation_margin(dnskey_get_activate_epoch(key), deactivate_epochus / ONE_SECOND_US, unpublish_epochus / ONE_SECOND_US);
2553
2554 time_t deactivate_epoch = (deactivate_epochus / ONE_SECOND_US) + deactivate_epoch_margin;
2555
2556 keyroll_step_t *deactivation_step = keyroll_get_step(keyroll, deactivate_epoch * ONE_SECOND_US);
2557 deactivation_step->keyroll_action |= /*KeyrollAction::*/Deactivate;
2558 deactivation_step->dirty = TRUE;
2559
2560 dnskey_set_inactive_epoch(key, deactivate_epoch);
2561
2562 if(*next_deactivationp < deactivate_epochus)
2563 {
2564 *next_deactivationp = deactivate_epochus;
2565 }
2566
2567 keyroll_step_t *unpublication_step = keyroll_get_step(keyroll, unpublish_epochus);
2568 ptr_vector_append(&unpublication_step->dnskey_del, key);
2569 dnskey_acquire(key);
2570 unpublication_step->keyroll_action |= /*KeyrollAction::*/Unpublish;
2571 unpublication_step->dirty = TRUE;
2572 time_t unpublish_epoch = MAX(unpublish_epochus / ONE_SECOND_US, deactivate_epoch);
2573 dnskey_set_delete_epoch(key, unpublish_epoch);
2574 dnssec_keystore_add_key(key);
2575 #if DEBUG
2576 log_debug("created key: domain=%{dnsname}, tag=%i, algorithm=%i, flags=%i, create=%U publish=%U activate=%U deactivate=%U unpublish=%U",
2577 dnskey_get_domain(key),
2578 dnskey_get_tag(key),
2579 dnskey_get_algorithm(key),
2580 ntohs(dnskey_get_flags(key)),
2581 dnskey_get_created_epoch(key),
2582 dnskey_get_publish_epoch(key),
2583 dnskey_get_activate_epoch(key),
2584 dnskey_get_inactive_epoch(key),
2585 dnskey_get_delete_epoch(key));
2586 logger_flush();
2587 #endif
2588 dnskey_release(key); // the original reference
2589 }
2590 else
2591 { // note: %llU => prints UTC time
2592 log_err("%{dnsname}: failed to generate %cSK key to publish at %llU: %r", keyroll->domain, ksk?'K':'Z', publication_epochus, ret);
2593 }
2594
2595 break;
2596 } // while(!dnscore_isshuttingdown())
2597
2598 if(ISOK(ret) && (out_keyp != NULL))
2599 {
2600 dnskey_acquire(key);
2601 *out_keyp = key;
2602 }
2603
2604 return ret;
2605 }
2606
2607 /**
2608 * Generates a plan using a DNSSEC policy.
2609 */
2610
2611 ya_result
keyroll_plan_with_policy(keyroll_t * keyroll,s64 generate_from,s64 generate_until,const char * policy_name)2612 keyroll_plan_with_policy(keyroll_t *keyroll, s64 generate_from, s64 generate_until, const char* policy_name)
2613 {
2614 dnssec_policy *policy = dnssec_policy_acquire_from_name(policy_name);
2615
2616 if(policy == NULL)
2617 {
2618 return UNEXPECTED_NULL_ARGUMENT_ERROR;
2619 }
2620
2621 ya_result ret;
2622
2623 ret = dnssec_policy_process(keyroll, policy, generate_from, generate_until);
2624
2625 // dnssec_policy_date_init_from_epoch
2626
2627 return ret;
2628 }
2629
2630 static u32
keyroll_key_hash(dnssec_key * key)2631 keyroll_key_hash(dnssec_key *key)
2632 {
2633 u32 key_hash = dnskey_get_flags(key);
2634 key_hash <<= 5;
2635 key_hash |= dnskey_get_algorithm(key);
2636 key_hash <<= 16;
2637 key_hash |= dnskey_get_tag(key);
2638 return key_hash;
2639 }
2640
2641 static void
keyroll_print_u32_set_destroy_callback(u32_node * node)2642 keyroll_print_u32_set_destroy_callback(u32_node *node)
2643 {
2644 dnssec_key *key = (dnssec_key*)node->value;
2645 dnskey_release(key);
2646 }
2647
2648 void
keyroll_step_print(keyroll_step_t * step)2649 keyroll_step_print(keyroll_step_t *step)
2650 {
2651 log_info("================================");
2652 log_info("At %llU = %llu", step->epochus, step->epochus);
2653 log_info("================================");
2654
2655 log_info("- update -----------------------");
2656
2657 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
2658 {
2659 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
2660 log_info("del record K%{dnsname}+%03u+%05d %-5i bits %cSK %U => %U => %U => %U", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key),
2661 dnskey_get_size(key), ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z', dnskey_get_publish_epoch(key), dnskey_get_activate_epoch(key),
2662 dnskey_get_inactive_epoch(key), dnskey_get_delete_epoch(key));
2663 }
2664
2665 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_add); ++i)
2666 {
2667 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_add, i);
2668 log_info("add record K%{dnsname}+%03u+%05d %-5i bits %cSK %U => %U => %U => %U", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key),
2669 dnskey_get_size(key), ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z', dnskey_get_publish_epoch(key), dnskey_get_activate_epoch(key),
2670 dnskey_get_inactive_epoch(key), dnskey_get_delete_epoch(key));
2671 }
2672
2673 for(int i = 0; i <= ptr_vector_last_index(&step->rrsig_add); ++i)
2674 {
2675 dns_resource_record *rr = (dns_resource_record*)ptr_vector_get(&step->rrsig_add, i);
2676 log_info("add record %{dnsrr}", rr);
2677 }
2678
2679 for(int i = 0; i <= ptr_vector_last_index(&step->expect); ++i)
2680 {
2681 dns_resource_record *rr = (dns_resource_record*)ptr_vector_get(&step->expect, i);
2682 log_info("expects record %{dnsrr}", rr);
2683 }
2684
2685 for(int i = 0; i <= ptr_vector_last_index(&step->file_del); ++i)
2686 {
2687 char *filename = (char*)ptr_vector_get(&step->file_del, i);
2688 log_info("delete file '%s'", filename);
2689 }
2690
2691 ptr_set_iterator iter;
2692 ptr_set_iterator_init(&step->file_add, &iter);
2693 while(ptr_set_iterator_hasnext(&iter))
2694 {
2695 ptr_node *node = ptr_set_iterator_next_node(&iter);
2696 char *filename = (char*)node->key;
2697 log_info("create file '%s'", filename);
2698 }
2699 }
2700
2701 #define log_print_info(...) log_info(__VA_ARGS__);formatln(__VA_ARGS__)
2702 #define log_print_warn(...) log_warn(__VA_ARGS__);formatln("WARNING: " __VA_ARGS__)
2703
2704 /**
2705 * Prints a plan.
2706 */
2707
2708 ya_result
keyroll_print(keyroll_t * keyroll,output_stream * os)2709 keyroll_print(keyroll_t *keyroll, output_stream *os)
2710 {
2711 ya_result ret = SUCCESS;
2712
2713 u32_set current;
2714 u32_set_init(¤t);
2715
2716 s64 ksk_next_deactivation = 0;
2717 s64 zsk_next_deactivation = 0;
2718
2719 u64_set_iterator iter;
2720 u64_set_iterator_init(&keyroll->steps, &iter);
2721
2722 if(!u64_set_iterator_hasnext(&iter))
2723 {
2724 osprintln(os, "*** ERROR *** No steps have been loaded");
2725 return INVALID_STATE_ERROR;
2726 }
2727
2728 while(u64_set_iterator_hasnext(&iter))
2729 {
2730 u64_node *step_node = u64_set_iterator_next_node(&iter);
2731 keyroll_step_t *step = (keyroll_step_t*)step_node->value;
2732
2733 if(step == NULL)
2734 {
2735 osformatln(os, "*** ERROR *** Empty step at %llU", step_node->key);
2736 continue;
2737 }
2738
2739 osprintln(os, "================================================================================");
2740 osformatln(os, "At %llU (epoch %llu)", step->epochus, step->epochus);
2741 osprintln(os, "================================================================================");
2742
2743 time_t now = (time_t)(step->epochus / ONE_SECOND_US);
2744
2745 osprintln(os, "DNS updates:");
2746 osprintln(os, "------------");
2747
2748 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
2749 {
2750 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
2751 formatln("del K%{dnsname}+%03u+%05d %-5i bits %cSK publish at %U, activate at %U, deactivate at %U, unpublish at %U",
2752 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key),
2753 dnskey_get_size(key), ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z',
2754 dnskey_get_publish_epoch(key), dnskey_get_activate_epoch(key),
2755 dnskey_get_inactive_epoch(key), dnskey_get_delete_epoch(key));
2756
2757 u32 key_hash = keyroll_key_hash(key);
2758 u32_node *node = u32_set_find(¤t, key_hash);
2759 if(node != NULL)
2760 {
2761 dnssec_key *node_key = (dnssec_key*)node->value;
2762 dnskey_release(node_key);
2763 u32_set_delete(¤t, key_hash);
2764 }
2765 else
2766 {
2767 osprintln(os, "*** WARNING *** Key isn't in the current set");
2768 }
2769 }
2770
2771 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_add); ++i)
2772 {
2773 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_add, i);
2774 osformatln(os, "add K%{dnsname}+%03u+%05d %-5i bits %cSK publish at %U, activate at %U, deactivate at %U, unpublish at %U",
2775 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key),
2776 dnskey_get_size(key), ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z',
2777 dnskey_get_publish_epoch(key), dnskey_get_activate_epoch(key),
2778 dnskey_get_inactive_epoch(key), dnskey_get_delete_epoch(key));
2779
2780 u32 key_hash = keyroll_key_hash(key);
2781 u32_node *node = u32_set_find(¤t, key_hash);
2782 if(node == NULL)
2783 {
2784 node = u32_set_insert(¤t, key_hash);
2785 node->value = key;
2786 dnskey_acquire(key);
2787 }
2788 else
2789 {
2790 osprintln(os, "*** WARNING *** Key is in the current set already");
2791 }
2792 }
2793
2794 osprintln(os, "DNS state:");
2795 osprintln(os, "----------");
2796
2797 {
2798 bool has_active_ksk = FALSE;
2799 bool has_active_zsk = FALSE;
2800
2801 u32_set_iterator iter;
2802 u32_set_iterator_init(¤t, &iter);
2803 while(u32_set_iterator_hasnext(&iter))
2804 {
2805 u32_node *node = u32_set_iterator_next_node(&iter);
2806 dnssec_key *key = (dnssec_key*)node->value;
2807 bool published = dnskey_is_published(key, now);
2808 bool activated = dnskey_is_activated(key, now);
2809 bool deactivated = dnskey_is_deactivated(key, now);
2810 bool unpublished = dnskey_is_unpublished(key, now);
2811
2812 if((dnskey_get_flags(key) & DNSKEY_FLAG_KEYSIGNINGKEY) != 0)
2813 {
2814 has_active_ksk |= activated;
2815 ksk_next_deactivation = ONE_SECOND_US * dnskey_get_inactive_epoch(key);
2816 }
2817 else
2818 {
2819 has_active_zsk |= activated;
2820 zsk_next_deactivation = ONE_SECOND_US * dnskey_get_inactive_epoch(key);
2821 }
2822
2823 osformatln(os, "=== K%{dnsname}+%03u+%05d %cSK %c %c %c %c", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key),
2824 ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z',
2825 (published?'P':'-'),
2826 (activated?'A':'-'),
2827 (deactivated?'D':'-'),
2828 (unpublished?'U':'-') // this one should not appear
2829 );
2830 }
2831
2832 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
2833 {
2834 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
2835 osformatln(os, "=== K%{dnsname}+%03u+%05d %cSK - - D U", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key),
2836 ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z');
2837 }
2838
2839 }
2840
2841 flushout();
2842 }
2843
2844 if((ksk_next_deactivation > 0) || (zsk_next_deactivation > 0))
2845 {
2846 osprintln(os, "- wrapping up ------------------");
2847
2848 if(ksk_next_deactivation > 0)
2849 {
2850 osformatln(os, "Next KSK will need to be active way before %llU", ksk_next_deactivation);
2851 }
2852
2853 if(zsk_next_deactivation > 0)
2854 {
2855 osformatln(os, "Next ZSK will need to be active way before %llU", zsk_next_deactivation);
2856 }
2857 }
2858
2859 u32_set_callback_and_destroy(¤t, keyroll_print_u32_set_destroy_callback);
2860
2861 return ret;
2862 }
2863
2864 /**
2865 * Prints a plan.
2866 */
2867
2868 ya_result
keyroll_print_json(keyroll_t * keyroll,output_stream * os)2869 keyroll_print_json(keyroll_t *keyroll, output_stream *os)
2870 {
2871 ya_result ret = SUCCESS;
2872
2873 if((keyroll == NULL) || (os == NULL))
2874 {
2875 return UNEXPECTED_NULL_ARGUMENT_ERROR;
2876 }
2877
2878 u32_set current;
2879 u32_set_init(¤t);
2880
2881 s64 ksk_next_deactivation = 0;
2882 s64 zsk_next_deactivation = 0;
2883
2884 u64_set_iterator iter;
2885 u64_set_iterator_init(&keyroll->steps, &iter);
2886
2887 if(!u64_set_iterator_hasnext(&iter))
2888 {
2889 return INVALID_STATE_ERROR;
2890 }
2891
2892 osformatln(os, "{\"domain\": \"%{dnsname}\", \"steps\": [", keyroll->domain);
2893
2894 const char *step_separator = "";
2895 while(u64_set_iterator_hasnext(&iter))
2896 {
2897 u64_node *step_node = u64_set_iterator_next_node(&iter);
2898 keyroll_step_t *step = (keyroll_step_t*)step_node->value;
2899
2900 osformat(os, step_separator);
2901 step_separator = ", ";
2902
2903 if(step == NULL)
2904 {
2905 log_print_info("*** ERROR *** EMPTY STEP AT %llU", step_node->key);
2906 osformat(os, "{\"time\": \"%llU\", \"epoch\": %llu}\n", step_node->key, step_node->key);
2907 continue;
2908 }
2909
2910 time_t now = (time_t)(step->epochus / ONE_SECOND_US);
2911
2912 osformat(os, "{\"time\": \"%llU\", \"epochUs\": %llu, \"updates\": [", step_node->key, step_node->key);
2913
2914 const char *update_separator = "";
2915
2916 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
2917 {
2918 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
2919
2920 osformat(os, "%s{\"operation\": \"delete\", \"algorithm\": %u, \"tag\": %u, \"size\": %u, \"flags\": \"%cZK\", "
2921 "\"publish\": \"%lU\", "
2922 "\"activate\": \"%lU\", "
2923 "\"deactivate\": \"%lU\", "
2924 "\"unpublish\": \"%lU\", "
2925 "\"publishEpoch\": \"%llu\", "
2926 "\"activateEpoch\": \"%llu\", "
2927 "\"deactivateEpoch\": \"%llu\", "
2928 "\"unpublishEpoch\": \"%llu\""
2929 "}\n",
2930 update_separator,
2931 dnskey_get_algorithm(key), dnskey_get_tag(key),
2932 dnskey_get_size(key), ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z',
2933 time_to_timeus(dnskey_get_publish_epoch(key)), time_to_timeus(dnskey_get_activate_epoch(key)),
2934 time_to_timeus(dnskey_get_inactive_epoch(key)), time_to_timeus(dnskey_get_delete_epoch(key)),
2935 dnskey_get_publish_epoch(key), dnskey_get_activate_epoch(key),
2936 dnskey_get_inactive_epoch(key), dnskey_get_delete_epoch(key));
2937
2938 update_separator = ", ";
2939
2940 u32 key_hash = keyroll_key_hash(key);
2941 u32_node *node = u32_set_find(¤t, key_hash);
2942 if(node != NULL)
2943 {
2944 dnssec_key *node_key = (dnssec_key*)node->value;
2945 dnskey_release(node_key);
2946 u32_set_delete(¤t, key_hash);
2947 }
2948 else
2949 {
2950 // log_print_warn("key isn't in the current set");
2951 }
2952 }
2953
2954 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_add); ++i)
2955 {
2956 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_add, i);
2957
2958 osformat(os, "%s{\"operation\": \"add\", \"algorithm\": %u, \"tag\": %u, \"size\": %u, \"flags\": \"%cZK\", "
2959 "\"publish\": \"%lU\", "
2960 "\"activate\": \"%lU\", "
2961 "\"deactivate\": \"%lU\", "
2962 "\"unpublish\": \"%lU\", "
2963 "\"publishEpoch\": \"%llu\", "
2964 "\"activateEpoch\": \"%llu\", "
2965 "\"deactivateEpoch\": \"%llu\", "
2966 "\"unpublishEpoch\": \"%llu\""
2967 "}\n",
2968 update_separator,
2969 dnskey_get_algorithm(key), dnskey_get_tag(key),
2970 dnskey_get_size(key), ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z',
2971 time_to_timeus(dnskey_get_publish_epoch(key)), time_to_timeus(dnskey_get_activate_epoch(key)),
2972 time_to_timeus(dnskey_get_inactive_epoch(key)), time_to_timeus(dnskey_get_delete_epoch(key)),
2973 dnskey_get_publish_epoch(key), dnskey_get_activate_epoch(key),
2974 dnskey_get_inactive_epoch(key), dnskey_get_delete_epoch(key));
2975
2976 update_separator = ", ";
2977
2978 u32 key_hash = keyroll_key_hash(key);
2979 u32_node *node = u32_set_find(¤t, key_hash);
2980 if(node == NULL)
2981 {
2982 node = u32_set_insert(¤t, key_hash);
2983 node->value = key;
2984 dnskey_acquire(key);
2985 }
2986 else
2987 {
2988 //log_print_warn("key is in the current set already");
2989 }
2990 }
2991
2992 osformat(os, "], \"keyState\": [");
2993
2994 const char *keystate_separator = "";
2995
2996 {
2997 bool has_active_ksk = FALSE;
2998 bool has_active_zsk = FALSE;
2999
3000 u32_set_iterator iter;
3001 u32_set_iterator_init(¤t, &iter);
3002 while(u32_set_iterator_hasnext(&iter))
3003 {
3004 u32_node *node = u32_set_iterator_next_node(&iter);
3005 dnssec_key *key = (dnssec_key*)node->value;
3006 bool published = dnskey_is_published(key, now);
3007 bool activated = dnskey_is_activated(key, now);
3008 bool deactivated = dnskey_is_deactivated(key, now);
3009 bool unpublished = dnskey_is_unpublished(key, now);
3010
3011 if((dnskey_get_flags(key) & DNSKEY_FLAG_KEYSIGNINGKEY) != 0)
3012 {
3013 has_active_ksk |= activated;
3014 ksk_next_deactivation = ONE_SECOND_US * dnskey_get_inactive_epoch(key);
3015 }
3016 else
3017 {
3018 has_active_zsk |= activated;
3019 zsk_next_deactivation = ONE_SECOND_US * dnskey_get_inactive_epoch(key);
3020 }
3021
3022 osformat(os, "%s{\"algorithm\": %u, \"tag\": %u, \"flags\": \"%cSK\", \"published\": %s, \"activated\": %s, \"deactivated\": %s, \"unpublished\": %s}\n",
3023 keystate_separator,
3024 dnskey_get_algorithm(key), dnskey_get_tag(key),
3025 ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z',
3026 (published?"true":"false"),
3027 (activated?"true":"false"),
3028 (deactivated?"true":"false"),
3029 (unpublished?"true":"false")
3030 );
3031 keystate_separator = ", ";
3032 }
3033
3034 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
3035 {
3036 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
3037 osformat(os, "%s{\"algorithm\": %u, \"tag\": %u, \"flags\": \"%cSK\", \"published\": false, \"activated\": false, \"deactivated\": true, \"unpublished\": true}\n",
3038 keystate_separator,
3039 dnskey_get_algorithm(key), dnskey_get_tag(key),
3040 ((dnskey_get_flags(key)&DNSKEY_FLAG_KEYSIGNINGKEY)!=0)?'K':'Z'
3041 );
3042 keystate_separator = ", ";
3043 }
3044 }
3045 osformat(os,"]}");
3046 }
3047
3048 osformat(os,"], \"followUp\": {\"nextKeySigningKeyActivationRequiredAt\": \"%llU\", \"nextZoneSigningKeyActivationRequiredAt\": \"%llU\"}",
3049 ksk_next_deactivation,
3050 zsk_next_deactivation
3051 );
3052
3053 osformatln(os, "}\n");
3054
3055 u32_set_callback_and_destroy(¤t, keyroll_print_u32_set_destroy_callback);
3056
3057 return ret;
3058 }
3059
3060
3061
3062 /**
3063 * Stores the plan on disk (several files, private KSK files, ...)
3064 */
3065
3066 ya_result
keyroll_store(keyroll_t * keyroll)3067 keyroll_store(keyroll_t *keyroll)
3068 {
3069 ya_result ret = SUCCESS;
3070
3071 u32_set current;
3072 u32_set_init(¤t);
3073
3074 ptr_vector expected_rrsig;
3075 ptr_vector_init_ex(&expected_rrsig, 16);
3076
3077 output_stream baos;
3078 output_stream previous_end_result_os;
3079 char file_path[PATH_MAX];
3080 u8 *rdata = (u8*)file_path; // both buffers can coexist
3081
3082 bytearray_output_stream_init(&baos, NULL, 8192);
3083
3084 bytearray_output_stream_init(&previous_end_result_os, NULL, 8192);
3085
3086 u64_set_iterator iter;
3087 u64_set_iterator_init(&keyroll->steps, &iter);
3088 while(u64_set_iterator_hasnext(&iter))
3089 {
3090 u64_node *node = u64_set_iterator_next_node(&iter);
3091 keyroll_step_t *step = (keyroll_step_t*)node->value;
3092
3093 if(step == NULL)
3094 {
3095 continue;
3096 }
3097
3098 if(!step->dirty)
3099 {
3100 continue;
3101 }
3102
3103 // look for the next signature update
3104
3105 s32 next_signature_update_epoch = MAX_S32;
3106
3107 for(keyroll_step_t *next_step = step; ;)
3108 {
3109 next_step = keyroll_get_next_step_from(keyroll, next_step->epochus + 1);
3110
3111 if(next_step == NULL)
3112 {
3113 break;
3114 }
3115
3116 if((ptr_vector_size(&next_step->dnskey_add) + ptr_vector_size(&next_step->dnskey_del)) > 0)
3117 {
3118 next_signature_update_epoch = (next_step->epochus / ONE_SECOND_US);
3119
3120 next_signature_update_epoch = (s32)MIN((s64)next_signature_update_epoch + NEXT_SIGNATURE_EPOCH_MARGIN, (s64)MAX_S32);
3121
3122 break;
3123 }
3124 }
3125
3126 bool has_zsk = FALSE;
3127 bool has_ksk = FALSE;
3128
3129 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_add); ++i)
3130 {
3131 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_add, i);
3132 has_ksk |= (dnskey_get_flags(key) == DNSKEY_FLAGS_KSK);
3133 has_zsk |= (dnskey_get_flags(key) == DNSKEY_FLAGS_ZSK);
3134 }
3135
3136 snformat(file_path, sizeof(file_path) - 16, "%s/%llU_%016lli_%{dnsname}", keyroll->plan_path, node->key, node->key, keyroll->domain);
3137 for(int i = 0; file_path[i] != '\0'; ++i)
3138 {
3139 if(file_path[i] == ' ')
3140 {
3141 file_path[i] = '-';
3142 }
3143 }
3144
3145 log_info("storing '%s'", file_path);
3146
3147 output_stream fos;
3148 ret = file_output_stream_create(&fos, file_path, 0644);
3149 if(FAIL(ret))
3150 {
3151 log_info("failed to create '%s': %r", file_path, ret);
3152 return ret;
3153 }
3154
3155 buffer_output_stream_init(&fos, &fos, 4096);
3156
3157 osformatln(&fos, "epochus %llu", step->epochus);
3158 osformatln(&fos, "dateus %llU", step->epochus);
3159 osprintln(&fos, "version " YKEYROLL_VERSION);
3160 osprint(&fos, "actions");
3161
3162 if(step->keyroll_action != 0)
3163 {
3164 if(step->keyroll_action & Publish) // add commands
3165 {
3166 osprint(&fos, " publish");
3167 }
3168 if(step->keyroll_action & Activate)
3169 {
3170 osprint(&fos, " activate");
3171 }
3172 if(step->keyroll_action & Deactivate)
3173 {
3174 osprint(&fos, " deactivate");
3175 }
3176 if(step->keyroll_action & Unpublish) // delete commands
3177 {
3178 osprint(&fos, " unpublish");
3179 }
3180 }
3181 else
3182 {
3183 osprint(&fos, " none");
3184 }
3185 osprintln(&fos, "");
3186
3187 {
3188 u8 *previous_end_result_text = bytearray_output_stream_buffer(&previous_end_result_os);
3189 u32 previous_end_result_size = bytearray_output_stream_size(&previous_end_result_os);
3190 output_stream_write(&fos, previous_end_result_text, previous_end_result_size);
3191 bytearray_output_stream_reset(&previous_end_result_os);
3192 }
3193
3194 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
3195 {
3196 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
3197 if(dnskey_get_flags(key) == DNSKEY_FLAGS_ZSK)
3198 {
3199 osformat(&fos, "del K%{dnsname}+%03u+%05d.key ", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key));
3200 bytearray_output_stream_reset(&baos);
3201 dnskey_store_public_key_to_stream(key, &baos);
3202 osprint_base64(&fos, bytearray_output_stream_buffer(&baos), bytearray_output_stream_size(&baos));
3203 osprintln(&fos, "");
3204
3205 #define NOTHING_TO_SEE_HERE_BASE64 "IyBub3RoaW5nIHRvIHNlZSBoZXJlCg=="
3206
3207 osformatln(&fos, "del K%{dnsname}+%03u+%05d.private " NOTHING_TO_SEE_HERE_BASE64, dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key));
3208 }
3209 else
3210 {
3211 // the file is not supposed to be transferred : there is nothing to delete
3212 }
3213 }
3214
3215 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_add); ++i)
3216 {
3217 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_add, i);
3218
3219 if(dnskey_get_flags(key) == DNSKEY_FLAGS_ZSK)
3220 {
3221 osformat(&fos, "add K%{dnsname}+%03u+%05d.key ", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key));
3222 bytearray_output_stream_reset(&baos);
3223 dnskey_store_public_key_to_stream(key, &baos);
3224 osprint_base64(&fos, bytearray_output_stream_buffer(&baos), bytearray_output_stream_size(&baos));
3225 osprintln(&fos, "");
3226
3227 osformat(&fos, "add K%{dnsname}+%03u+%05d.private ", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key));
3228 bytearray_output_stream_reset(&baos);
3229 dnskey_store_private_key_to_stream(key, &baos);
3230 osprint_base64(&fos, bytearray_output_stream_buffer(&baos), bytearray_output_stream_size(&baos));
3231 osprintln(&fos, "");
3232
3233 osformatln(&fos, "debug tag=%i flags=%s created=%U publish=%U activate=%U deactivate=%U unpublish=%U",
3234 dnskey_get_tag(key), ((dnskey_get_flags(key) == DNSKEY_FLAGS_KSK)?"KSK":"ZSK"),
3235 dnskey_get_created_epoch(key), dnskey_get_publish_epoch(key),
3236 dnskey_get_activate_epoch(key), dnskey_get_inactive_epoch(key),
3237 dnskey_get_delete_epoch(key));
3238 }
3239 else
3240 {
3241 // store the private key separately
3242
3243 dnssec_keystore_add_domain(keyroll->domain, keyroll->private_keys_path);
3244
3245 if(FAIL(ret = dnssec_keystore_store_private_key(key)))
3246 {
3247 log_err("could not store private key-signing key");
3248 return ret;
3249 }
3250
3251 if(FAIL(ret = dnssec_keystore_store_public_key(key)))
3252 {
3253 log_err("could not store public key-signing key");
3254 return ret;
3255 }
3256 }
3257 }
3258
3259 bool has_changes = (ptr_vector_size(&step->dnskey_del) + ptr_vector_size(&step->dnskey_add)) > 0;
3260
3261 if(has_changes)
3262 {
3263 // signatures will be cleared as soon as this happens (change(s) in the DNSKEY rrset)
3264 /*
3265 // now the rrsig is held by the step
3266
3267 for(int i = 0; i <= ptr_vector_last_index(&expected_rrsig); ++i)
3268 {
3269 dns_resource_record *rrsig = (dns_resource_record*)ptr_vector_get(&expected_rrsig, i);
3270 dns_resource_record_finalize(rrsig);
3271 }
3272 */
3273 ptr_vector_clear(&expected_rrsig);
3274
3275 // the DNSKEY records to delete
3276
3277 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_del); ++i)
3278 {
3279 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_del, i);
3280
3281 int rdata_size = key->vtbl->dnssec_key_writerdata(key, rdata, PATH_MAX);
3282 rdata_desc dnskeyrdata = {TYPE_DNSKEY, rdata_size, rdata};
3283
3284 osformatln(&fos, "update delete %{dnsname} %i %{typerdatadesc}", keyroll->domain, TTL, &dnskeyrdata);
3285
3286 u32 key_hash = keyroll_key_hash(key);
3287 u32_node *node = u32_set_find(¤t, key_hash);
3288 if(node != NULL)
3289 {
3290 dnssec_key *node_key = (dnssec_key*)node->value;
3291 dnskey_release(node_key);
3292 u32_set_delete(¤t, key_hash);
3293 }
3294 }
3295
3296 // the DNSKEY records to add
3297
3298 for(int i = 0; i <= ptr_vector_last_index(&step->dnskey_add); ++i)
3299 {
3300 dnssec_key *key = (dnssec_key*)ptr_vector_get(&step->dnskey_add, i);
3301
3302 int rdata_size = key->vtbl->dnssec_key_writerdata(key, rdata, PATH_MAX);
3303 rdata_desc dnskeyrdata = {TYPE_DNSKEY, rdata_size, rdata};
3304
3305 osformatln(&fos, "update add %{dnsname} %i %{typerdatadesc}", keyroll->domain, TTL, &dnskeyrdata);
3306
3307 u32 key_hash = keyroll_key_hash(key);
3308 u32_node *node = u32_set_find(¤t, key_hash);
3309 if(node == NULL)
3310 {
3311 node = u32_set_insert(¤t, key_hash);
3312 node->value = key;
3313 dnskey_acquire(key);
3314 }
3315 }
3316
3317 // the RRSIG records to add
3318
3319 {
3320 struct resource_record_view rrv;
3321 dnskey_signature ds;
3322
3323 // the signature should cover the earliest key deletion
3324 // the signature should cover the earliest ksk deactivation
3325
3326 dns_resource_record *rrsig;
3327
3328 // build the set of records
3329
3330 ptr_vector rrset;
3331 ptr_vector_init(&rrset);
3332
3333 u32_set_iterator iter;
3334 u32_set_iterator_init(¤t, &iter);
3335 while(u32_set_iterator_hasnext(&iter))
3336 {
3337 u32_node *node = u32_set_iterator_next_node(&iter);
3338 dnssec_key *key = (dnssec_key*)node->value;
3339
3340 int rdata_size = key->vtbl->dnssec_key_writerdata(key, rdata, PATH_MAX);
3341 rdata_desc dnskeyrdata = {TYPE_DNSKEY, rdata_size, rdata};
3342 osformatln(&fos, "endresult %{dnsname} %i %{typerdatadesc}", keyroll->domain, TTL, &dnskeyrdata);
3343 osformatln(&previous_end_result_os, "expect %{dnsname} %i %{typerdatadesc}", keyroll->domain, TTL, &dnskeyrdata);
3344
3345 dns_resource_record *rr = dns_resource_record_new_instance();
3346 dnskey_init_dns_resource_record(key, TTL, rr);
3347
3348 ptr_vector_append(&rrset, rr);
3349 }
3350
3351 // for all active KSK, generate a signature
3352
3353 u32_set_iterator_init(¤t, &iter);
3354 while(u32_set_iterator_hasnext(&iter))
3355 {
3356 u32_node *node = u32_set_iterator_next_node(&iter);
3357 dnssec_key *key = (dnssec_key*)node->value;
3358
3359 if(dnskey_get_flags(key) == DNSKEY_FLAGS_KSK)
3360 {
3361 dns_resource_record_resource_record_view_init(&rrv);
3362 dnskey_signature_init(&ds);
3363 s32 from = (step->epochus / ONE_SECOND_US) - RRSIG_ANTEDATING; // sign from the day before
3364
3365 log_debug("%{dnsname}: %llT signing DNSKEY RRSET with key %hu, inactive at %T (%T)",
3366 keyroll->domain, step->epochus, dnskey_get_tag(key),
3367 dnskey_get_inactive_epoch(key), next_signature_update_epoch);
3368
3369 if(dnskey_get_inactive_epoch(key) > next_signature_update_epoch)
3370 {
3371 log_debug("%{dnsname}: %llT key %hu is inactive at %T which is after the planned expiration time %T",
3372 keyroll->domain, step->epochus, dnskey_get_tag(key),
3373 dnskey_get_inactive_epoch(key), next_signature_update_epoch);
3374 }
3375
3376 s32 to = MAX(dnskey_get_inactive_epoch(key), next_signature_update_epoch);
3377
3378 log_info("signing from %U to %U", from, to);
3379
3380 dnskey_signature_set_view(&ds, &rrv);
3381 dnskey_signature_set_validity(&ds, from, to);
3382 dnskey_signature_set_rrset_reference(&ds, &rrset);
3383 ret = dnskey_signature_sign(&ds, key, (void**)&rrsig);
3384 dnskey_signature_finalize(&ds);
3385
3386 if(FAIL(ret))
3387 {
3388 log_info("signature failed: %r", ret);
3389 return ret;
3390 }
3391
3392 osformatln(&fos, "update add %{dnszrr}", rrsig);
3393
3394 ptr_vector_append(&step->rrsig_add, rrsig);
3395
3396 ptr_vector_append(&expected_rrsig, rrsig);
3397 }
3398 }
3399
3400 for(int i = 0; i <= ptr_vector_last_index(&rrset); ++i)
3401 {
3402 dns_resource_record *rr = (dns_resource_record*)ptr_vector_get(&rrset, i);
3403 dns_resource_record_free(rr);
3404 }
3405
3406 ptr_vector_destroy(&rrset);
3407 } // current set sub-block
3408 } // has changes
3409 else
3410 {
3411 u32_set_iterator iter;
3412 u32_set_iterator_init(¤t, &iter);
3413 while(u32_set_iterator_hasnext(&iter))
3414 {
3415 u32_node *node = u32_set_iterator_next_node(&iter);
3416 dnssec_key *key = (dnssec_key*)node->value;
3417
3418 int rdata_size = key->vtbl->dnssec_key_writerdata(key, rdata, PATH_MAX);
3419 rdata_desc dnskeyrdata = {TYPE_DNSKEY, rdata_size, rdata};
3420
3421 osformatln(&fos, "endresult %{dnsname} %i %{typerdatadesc}", keyroll->domain, TTL, &dnskeyrdata);
3422 osformatln(&previous_end_result_os, "expect %{dnsname} %i %{typerdatadesc}", keyroll->domain, TTL, &dnskeyrdata);
3423 }
3424 }
3425
3426 for(int i = 0; i <= ptr_vector_last_index(&expected_rrsig); ++i)
3427 {
3428 dns_resource_record *rrsig = (dns_resource_record*)ptr_vector_get(&expected_rrsig, i);
3429 osformatln(&fos, "endresult %{dnszrr}", rrsig);
3430 osformatln(&previous_end_result_os, "expect %{dnszrr}", rrsig);
3431 }
3432
3433 output_stream_close(&fos);
3434
3435 flushout();
3436 }
3437
3438 /*
3439 // now the rrsig is held by the step
3440
3441 for(int i = 0; i <= ptr_vector_last_index(&expected_rrsig); ++i)
3442 {
3443 dns_resource_record *rrsig = (dns_resource_record*)ptr_vector_get(&expected_rrsig, i);
3444 dns_resource_record_finalize(rrsig);
3445 }
3446 */
3447 ptr_vector_destroy(&expected_rrsig);
3448
3449 u32_set_callback_and_destroy(¤t, keyroll_print_u32_set_destroy_callback);
3450
3451 return ret;
3452 }
3453
3454 /**
3455 *
3456 */
3457
3458 ya_result
keyroll_get_state_find_match_and_play(const keyroll_t * keyrollp,s64 now,const keyroll_step_t * current_step,const keyroll_step_t ** matched_stepp)3459 keyroll_get_state_find_match_and_play(const keyroll_t *keyrollp, s64 now, const keyroll_step_t *current_step, const keyroll_step_t **matched_stepp)
3460 {
3461 // check the expected set with the server
3462 // do a query for all DNSKEY + RRSIG and compare with the step
3463
3464 ya_result ret = STOPPED_BY_APPLICATION_SHUTDOWN;
3465
3466 u32 match_verify_try_count = 0;
3467
3468 ptr_vector current_dnskey_rrsig_rr;
3469 ptr_vector_init_ex(¤t_dnskey_rrsig_rr, 32);
3470 while(!dnscore_shuttingdown() && ISOK(ret = keyroll_dnskey_state_query(keyrollp, ¤t_dnskey_rrsig_rr)))
3471 {
3472 // current_dnskey_rrsig_rr contains the records currently on the server
3473
3474 ya_result matched_expectations = keyroll_step_expects_matched(current_step, ¤t_dnskey_rrsig_rr);
3475
3476 log_info("current step (%llU) expects to start from:", current_step->epochus);
3477
3478 for(int i = 0; i <= ptr_vector_last_index(¤t_step->expect); ++i)
3479 {
3480 log_info("%{dnszrr}", ptr_vector_get(¤t_step->expect, i));
3481 }
3482
3483 log_info("server (%{hostaddr}) has:", keyrollp->server);
3484
3485 for(int i = 0; i <= ptr_vector_last_index(¤t_dnskey_rrsig_rr); ++i)
3486 {
3487 log_info("%{dnszrr}", ptr_vector_get(¤t_dnskey_rrsig_rr, i));
3488 }
3489
3490 if(ISOK(matched_expectations))
3491 {
3492 log_debug("zone %{dnsname}: expectations are matched", current_step->keyroll->domain);
3493
3494 keyroll_dnskey_state_destroy(¤t_dnskey_rrsig_rr); // leads to an exit
3495
3496 ret = keyroll_step_play(current_step, FALSE);
3497
3498 if(matched_stepp != NULL)
3499 {
3500 *matched_stepp = current_step;
3501 }
3502
3503 return ret;
3504 }
3505 else
3506 {
3507 log_warn("zone %{dnsname} expectations are NOT matched", current_step->keyroll->domain);
3508
3509 bool nameserver_has_no_dnskey = (ptr_vector_last_index(¤t_dnskey_rrsig_rr) < 0);
3510
3511 if(nameserver_has_no_dnskey)
3512 {
3513 keyroll_dnskey_state_destroy(¤t_dnskey_rrsig_rr); // leads to an exit
3514
3515 // there are no keys on the server (and implicitely, some were expected)
3516 // so we start playing from the start until now
3517
3518 keyroll_step_t *first_step;
3519
3520 if(FAIL(ret = keyroll_play_first_step(keyrollp, now, &first_step)))
3521 {
3522 return ret;
3523 }
3524
3525 // now play all the steps until the one we are supposed to be currently in
3526
3527 ret = keyroll_step_play_range(keyrollp, first_step->epochus + 1 , now);
3528
3529 log_info("zone %{dnsname}: done replaying steps: %r", current_step->keyroll->domain, ret);
3530
3531 return ret;
3532 }
3533 else
3534 {
3535 log_info("zone %{dnsname}: scanning for a match", current_step->keyroll->domain);
3536
3537 keyroll_step_t* step = keyroll_step_scan_matching_expectations(keyrollp, ¤t_dnskey_rrsig_rr);
3538
3539 keyroll_dnskey_state_destroy(¤t_dnskey_rrsig_rr); // leads to an exit or loops
3540
3541 if(step == NULL)
3542 {
3543 log_info("zone %{dnsname}: no match found, looking for first step after %llU", current_step->keyroll->domain, now);
3544
3545 keyroll_step_t *first_step;
3546
3547 if(FAIL(ret = keyroll_play_first_step(keyrollp, now, &first_step)))
3548 {
3549 if(ret == MAKE_ERRNO_ERROR(EPERM))
3550 {
3551 log_err("zone %{dnsname}: failed to find step: %r (%i:%i)", current_step->keyroll->domain, ret, getuid(), getgid());
3552 }
3553 else
3554 {
3555 log_err("zone %{dnsname}: failed to play step: %r", current_step->keyroll->domain, ret);
3556 }
3557
3558 ++match_verify_try_count;
3559
3560 if(ret == MAKE_DNSMSG_ERROR(RCODE_SERVFAIL))
3561 {
3562 log_err("%{dnsname}: server cannot apply the update at the moment (try %i/%i)", current_step->keyroll->domain, match_verify_try_count, current_step->keyroll->match_verify_retries);
3563 }
3564 else
3565 {
3566 log_err("%{dnsname}: could not find a match (try %i/%i)", current_step->keyroll->domain, match_verify_try_count, current_step->keyroll->match_verify_retries);
3567 }
3568
3569 // 1 vs 1 => must do
3570 if(match_verify_try_count <= current_step->keyroll->match_verify_retries)
3571 {
3572 if(!dnscore_shuttingdown())
3573 {
3574 usleep_ex(ONE_SECOND_US * current_step->keyroll->match_verify_retries_delay);
3575 }
3576
3577 ptr_vector_init_ex(¤t_dnskey_rrsig_rr, 32); // because the array was destroyed
3578 ret = STOPPED_BY_APPLICATION_SHUTDOWN;
3579 continue;
3580 }
3581 else
3582 {
3583 return ret;
3584 }
3585 }
3586
3587 step = first_step;
3588 }
3589 else
3590 {
3591 log_info("zone %{dnsname}: match found at %llU", current_step->keyroll->domain, step->epochus);
3592 keyroll_step_print(step);
3593 log_info("--------------");
3594 }
3595
3596 if(now >= step->epochus + 1)
3597 {
3598 log_info("zone %{dnsname}: will play range from %llU until %llU", current_step->keyroll->domain, step->epochus + 1, now);
3599
3600 ret = keyroll_step_play_range(keyrollp, step->epochus + 1 , now);
3601
3602 log_info("zone %{dnsname}: done replaying steps: %r", current_step->keyroll->domain, ret);
3603 }
3604 else
3605 {
3606 log_info("zone %{dnsname}: no range to replay", current_step->keyroll->domain);
3607 }
3608
3609 // will end with a return ret;
3610 } // endif
3611 } // endif
3612
3613 break;
3614 }
3615
3616 return ret;
3617 }
3618
3619 void
keyroll_set_dryrun_mode(bool enabled)3620 keyroll_set_dryrun_mode(bool enabled)
3621 {
3622 keyroll_dryrun_mode = enabled;
3623 }
3624