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               &microseconds,
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(&current_dnskey_rrsig_rr, 32);
2062                         if(ISOK(ret = keyroll_dnskey_state_query(step->keyroll, &current_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, &current_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(&current_dnskey_rrsig_rr); ++i)
2078                             {
2079                                 log_info("%{dnszrr}", ptr_vector_get(&current_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(&current_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(&current);
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(&current, 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(&current, 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(&current, key_hash);
2782             if(node == NULL)
2783             {
2784                 node = u32_set_insert(&current, 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(&current, &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(&current, 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(&current);
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(&current, 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(&current, 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(&current, key_hash);
2980             if(node == NULL)
2981             {
2982                 node = u32_set_insert(&current, 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(&current, &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(&current, 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(&current);
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(&current, 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(&current, 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(&current, key_hash);
3309                 if(node == NULL)
3310                 {
3311                     node = u32_set_insert(&current, 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(&current, &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(&current, &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(&current, &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(&current, 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(&current_dnskey_rrsig_rr, 32);
3470     while(!dnscore_shuttingdown() && ISOK(ret = keyroll_dnskey_state_query(keyrollp, &current_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, &current_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(&current_step->expect); ++i)
3479         {
3480             log_info("%{dnszrr}", ptr_vector_get(&current_step->expect, i));
3481         }
3482 
3483         log_info("server (%{hostaddr}) has:", keyrollp->server);
3484 
3485         for(int i = 0; i <= ptr_vector_last_index(&current_dnskey_rrsig_rr); ++i)
3486         {
3487             log_info("%{dnszrr}", ptr_vector_get(&current_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(&current_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(&current_dnskey_rrsig_rr) < 0);
3510 
3511             if(nameserver_has_no_dnskey)
3512             {
3513                 keyroll_dnskey_state_destroy(&current_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, &current_dnskey_rrsig_rr);
3538 
3539                 keyroll_dnskey_state_destroy(&current_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(&current_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