3 /*****************************************************************
5 ** @(#) dnssec-zkt.c (c) Jan 2005 Holger Zuleger hznet.de
7 ** Secure DNS zone key tool
8 ** A wrapper command around the BIND dnssec-keygen utility
10 ** Copyright (c) 2005 - 2008, Holger Zuleger HZnet. All rights reserved.
12 ** This software is open source.
14 ** Redistribution and use in source and binary forms, with or without
15 ** modification, are permitted provided that the following conditions
18 ** Redistributions of source code must retain the above copyright notice,
19 ** this list of conditions and the following disclaimer.
21 ** Redistributions in binary form must reproduce the above copyright notice,
22 ** this list of conditions and the following disclaimer in the documentation
23 ** and/or other materials provided with the distribution.
25 ** Neither the name of Holger Zuleger HZnet nor the names of its contributors may
26 ** be used to endorse or promote products derived from this software without
27 ** specific prior written permission.
29 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
33 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 ** POSSIBILITY OF SUCH DAMAGE.
41 *****************************************************************/
44 # include <stdlib.h> /* abort(), exit(), ... */
54 # include "config_zkt.h"
55 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
72 char *labellist
= NULL
;
85 static int dirflag
= 0;
86 static int recflag
= RECURSIVE
;
87 static int trustedkeyflag
= 0;
88 static char *kskdomain
= "";
89 static const char *view
= "";
91 # define short_options ":0:1:2:3:9A:C:D:P:S:R:HKTs:ZV:afF:c:O:dhkLl:prtez"
92 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
93 static struct option long_options
[] = {
94 {"ksk-rollover", no_argument
, NULL
, '9'},
95 {"ksk-status", required_argument
, NULL
, '0'},
96 {"ksk-roll-status", required_argument
, NULL
, '0'},
97 {"ksk-newkey", required_argument
, NULL
, '1'},
98 {"ksk-publish", required_argument
, NULL
, '2'},
99 {"ksk-delkey", required_argument
, NULL
, '3'},
100 {"ksk-roll-phase1", required_argument
, NULL
, '1'},
101 {"ksk-roll-phase2", required_argument
, NULL
, '2'},
102 {"ksk-roll-phase3", required_argument
, NULL
, '3'},
103 {"list-dnskeys", no_argument
, NULL
, 'K'},
104 {"list-trustedkeys", no_argument
, NULL
, 'T'},
105 {"ksk", no_argument
, NULL
, 'k'},
106 {"zsk", no_argument
, NULL
, 'z'},
107 {"age", no_argument
, NULL
, 'a'},
108 {"lifetime", no_argument
, NULL
, 'f'},
109 {"time", no_argument
, NULL
, 't'},
110 {"expire", no_argument
, NULL
, 'e'},
111 {"recursive", no_argument
, NULL
, 'r'},
112 {"zone-config", no_argument
, NULL
, 'Z'},
113 {"leftjust", no_argument
, NULL
, 'L'},
114 {"path", no_argument
, NULL
, 'p'},
115 {"nohead", no_argument
, NULL
, 'h'},
116 {"directory", no_argument
, NULL
, 'd'},
117 {"config", required_argument
, NULL
, 'c'},
118 {"option", required_argument
, NULL
, 'O'},
119 {"config-option", required_argument
, NULL
, 'O'},
120 {"published", required_argument
, NULL
, 'P'},
121 {"standby", required_argument
, NULL
, 'S'},
122 {"active", required_argument
, NULL
, 'A'},
123 {"depreciated", required_argument
, NULL
, 'D'},
124 {"create", required_argument
, NULL
, 'C'},
125 {"revoke", required_argument
, NULL
, 'R'},
126 {"remove", required_argument
, NULL
, 19 },
127 {"destroy", required_argument
, NULL
, 20 },
128 {"setlifetime", required_argument
, NULL
, 'F' },
129 {"view", required_argument
, NULL
, 'V' },
130 {"help", no_argument
, NULL
, 'H'},
135 static int parsedirectory (const char *dir
, dki_t
**listp
);
136 static void parsefile (const char *file
, dki_t
**listp
);
137 static void createkey (const char *keyname
, const dki_t
*list
, const zconf_t
*conf
);
138 static void ksk_roll (const char *keyname
, int phase
, const dki_t
*list
, const zconf_t
*conf
);
139 static int create_parent_file (const char *fname
, int phase
, int ttl
, const dki_t
*dkp
);
140 static void usage (char *mesg
, zconf_t
*cp
);
141 static const char *parsetag (const char *str
, int *tagp
);
143 static void setglobalflags (zconf_t
*config
)
145 recflag
= config
->recursive
;
146 ageflag
= config
->printage
;
147 timeflag
= config
->printtime
;
148 ljustflag
= config
->ljust
;
151 int main (int argc
, char *argv
[])
159 const char *defconfname
= NULL
;
162 const char *keyname
= NULL
;
167 if ( (p
= strrchr (progname
, '/')) )
169 view
= getnameappendix (progname
, "dnssec-zkt");
171 defconfname
= getdefconfname (view
);
172 config
= loadconfig ("", (zconf_t
*)NULL
); /* load built in config */
173 if ( fileexist (defconfname
) ) /* load default config file */
174 config
= loadconfig (defconfname
, config
);
175 if ( config
== NULL
)
176 fatal ("Out of memory\n");
177 setglobalflags (config
);
182 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
183 while ( (c
= getopt_long (argc
, argv
, short_options
, long_options
, &opt_index
)) != -1 )
185 while ( (c
= getopt (argc
, argv
, short_options
)) != -1 )
190 case '9': /* ksk rollover help */
191 ksk_roll ("help", c
- '0', NULL
, NULL
);
193 case '1': /* ksk rollover: create new key */
194 case '2': /* ksk rollover: publish DS */
195 case '3': /* ksk rollover: delete old key */
196 case '0': /* ksk rollover: show current status */
199 usage ("ksk rollover requires an domain argument", config
);
200 kskdomain
= domain_canonicdup (optarg
);
204 zskflag
= pathflag
= 0;
212 pathflag
= !pathflag
;
222 if ( (keyname
= parsetag (optarg
, &searchtag
)) != NULL
)
223 keyname
= domain_canonicdup (keyname
);
229 case 'f': /* key lifetime */
230 lifetimeflag
= !lifetimeflag
;
232 case 'F': /* set key lifetime */
233 lifetime
= atoi (optarg
);
234 lifetimeflag
= 1; /* set some flags for more informative output */
239 case 'V': /* view name */
241 defconfname
= getdefconfname (view
);
242 if ( fileexist (defconfname
) ) /* load default config file */
243 config
= loadconfig (defconfname
, config
);
244 if ( config
== NULL
)
245 fatal ("Out of memory\n");
246 setglobalflags (config
);
249 config
= loadconfig (optarg
, config
);
250 setglobalflags (config
);
251 checkconfig (config
);
253 case 'O': /* read option from commandline */
254 config
= loadconfig_fromstr (optarg
, config
);
255 setglobalflags (config
);
256 checkconfig (config
);
258 case 'd': /* ignore directory arg */
261 case 'h': /* print no headline */
264 case 'k': /* ksk only */
267 case 'L': /* ljust */
268 ljustflag
= !ljustflag
;
270 case 'l': /* label list */
271 labellist
= prepstrlist (optarg
, LISTDELIM
);
272 if ( labellist
== NULL
)
273 fatal ("Out of memory\n");
275 case 'p': /* print path */
278 case 'r': /* switch recursive flag */
282 timeflag
= !timeflag
;
284 case 'e': /* expire time */
285 exptimeflag
= !exptimeflag
;
287 case 'z': /* zsk only */
291 snprintf (str
, sizeof(str
), "option \"-%c\" requires an argument.\n",
296 if ( isprint (optopt
) )
297 snprintf (str
, sizeof(str
), "Unknown option \"-%c\".\n",
300 snprintf (str
, sizeof (str
), "Unknown option char \\x%x.\n",
309 /* it's better to do this before we read the whole directory tree */
312 printconfig ("stdout", config
);
316 if ( kskflag
== 0 && zskflag
== 0 )
317 kskflag
= zskflag
= 1;
321 if ( c
>= argc
) /* no args left */
322 file
= config
->zonedir
; /* use default directory */
326 if ( is_directory (file
) )
327 parsedirectory (file
, &data
);
329 parsefile (file
, &data
);
331 } while ( c
< argc
); /* for all arguments */
338 createkey (keyname
, data
, config
);
344 if ( (dkp
= (dki_t
*)zkt_search (data
, searchtag
, keyname
)) == NULL
)
345 fatal ("Key with tag %u not found\n", searchtag
);
346 else if ( dkp
== (void *) 01 )
347 fatal ("Key with tag %u found multiple times\n", searchtag
);
348 if ( (c
= dki_setstatus_preservetime (dkp
, action
)) != 0 )
349 fatal ("Couldn't change status of key %u: %d\n", searchtag
, c
);
351 case 19: /* remove (rename) key file */
352 if ( (dkp
= (dki_t
*)zkt_search (data
, searchtag
, keyname
)) == NULL
)
353 fatal ("Key with tag %u not found\n", searchtag
);
354 else if ( dkp
== (void *) 01 )
355 fatal ("Key with tag %u found multiple times\n", searchtag
);
358 case 20: /* destroy the key (remove the files!) */
359 if ( (dkp
= (dki_t
*)zkt_search (data
, searchtag
, keyname
)) == NULL
)
360 fatal ("Key with tag %u not found\n", searchtag
);
361 else if ( dkp
== (void *) 01 )
362 fatal ("Key with tag %u found multiple times\n", searchtag
);
366 if ( (dkp
= (dki_t
*)zkt_search (data
, searchtag
, keyname
)) == NULL
)
367 fatal ("Key with tag %u not found\n", searchtag
);
368 else if ( dkp
== (void *) 01 )
369 fatal ("Key with tag %u found multiple times\n", searchtag
);
370 if ( (c
= dki_setstatus (dkp
, action
)) != 0 )
371 fatal ("Couldn't change status of key %u: %d\n", searchtag
, c
);
374 if ( (dkp
= (dki_t
*)zkt_search (data
, searchtag
, keyname
)) == NULL
)
375 fatal ("Key with tag %u not found\n", searchtag
);
376 else if ( dkp
== (void *) 01 )
377 fatal ("Key with tag %u found multiple times\n", searchtag
);
378 dki_prt_dnskey (dkp
, stdout
);
381 zkt_list_dnskeys (data
);
384 zkt_list_trustedkeys (data
);
386 case '1': /* ksk rollover new key */
387 case '2': /* ksk rollover publish DS */
388 case '3': /* ksk rollover delete old key */
389 case '0': /* ksk rollover status */
390 ksk_roll (kskdomain
, action
- '0', data
, config
);
393 zkt_setkeylifetime (data
);
396 zkt_list_keys (data
);
402 # define sopt_usage(mesg, value) fprintf (stderr, mesg, value)
403 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
404 # define lopt_usage(mesg, value) fprintf (stderr, mesg, value)
405 # define loptstr(lstr, sstr) lstr
407 # define lopt_usage(mesg, value)
408 # define loptstr(lstr, sstr) sstr
410 static void usage (char *mesg
, zconf_t
*cp
)
412 fprintf (stderr
, "Secure DNS Zone Key Tool %s\n", ZKT_VERSION
);
413 fprintf (stderr
, "\n");
414 fprintf (stderr
, "Show zone config parameter as %s file\n", LOCALCONF_FILE
);
415 sopt_usage ("\tusage: %s -Z\n", progname
);
416 lopt_usage ("\tusage: %s --zone-config\n", progname
);
417 fprintf (stderr
, "\n");
418 fprintf (stderr
, "List keys in current or given directory (-r for recursive mode)\n");
419 sopt_usage ("\tusage: %s [-dhatkzpr] [-c config] [file|dir ...]\n", progname
);
420 fprintf (stderr
, "\n");
421 fprintf (stderr
, "List public part of keys in DNSKEY RR format\n");
422 sopt_usage ("\tusage: %s -K [-dhkzr] [-c config] [file|dir ...]\n", progname
);
423 lopt_usage ("\tusage: %s --list-dnskeys [-dhkzr] [-c config] [file|dir ...]\n", progname
);
424 fprintf (stderr
, "\n");
425 fprintf (stderr
, "List keys (output is suitable for trusted-keys section)\n");
426 sopt_usage ("\tusage: %s -T [-dhzr] [-c config] [file|dir ...]\n", progname
);
427 lopt_usage ("\tusage: %s --list-trustedkeys [-dhzr] [-c config] [file|dir ...]\n", progname
);
428 fprintf (stderr
, "\n");
429 fprintf (stderr
, "Create a new key \n");
430 sopt_usage ("\tusage: %s -C <name> [-k] [-dpr] [-c config] [dir ...]\n", progname
);
431 lopt_usage ("\tusage: %s --create=<name> [-k] [-dpr] [-c config] [dir ...]\n", progname
);
432 fprintf (stderr
, "\t\tKSK (use -k): %s %d bits\n", dki_algo2str (cp
->k_algo
), cp
->k_bits
);
433 fprintf (stderr
, "\t\tZSK (default): %s %d bits\n", dki_algo2str (cp
->k_algo
), cp
->z_bits
);
434 fprintf (stderr
, "\n");
435 fprintf (stderr
, "Change key status of specified key to published, active or depreciated\n");
436 fprintf (stderr
, "\t(<keyspec> := tag | tag:name) \n");
437 sopt_usage ("\tusage: %s -P|-A|-D <keyspec> [-dr] [-c config] [dir ...]\n", progname
);
438 lopt_usage ("\tusage: %s --published=<keyspec> [-dr] [-c config] [dir ...]\n", progname
);
439 lopt_usage ("\tusage: %s --active=<keyspec> [-dr] [-c config] [dir ...]\n", progname
);
440 lopt_usage ("\tusage: %s --depreciated=<keyspec> [-dr] [-c config] [dir ...]\n", progname
);
441 fprintf (stderr
, "\n");
442 fprintf (stderr
, "Revoke specified key (<keyspec> := tag | tag:name) \n");
443 sopt_usage ("\tusage: %s -R <keyspec> [-dr] [-c config] [dir ...]\n", progname
);
444 lopt_usage ("\tusage: %s --revoke=<keyspec> [-dr] [-c config] [dir ...]\n", progname
);
445 fprintf (stderr
, "\n");
446 fprintf (stderr
, "Remove (rename) or destroy (delete) specified key (<keyspec> := tag | tag:name) \n");
447 lopt_usage ("\tusage: %s --remove=<keyspec> [-dr] [-c config] [dir ...]\n", progname
);
448 lopt_usage ("\tusage: %s --destroy=<keyspec> [-dr] [-c config] [dir ...]\n", progname
);
449 fprintf (stderr
, "\n");
450 fprintf (stderr
, "Initiate a semi-automated KSK rollover");
451 fprintf (stderr
, "('%s -9%s' prints out a short description)\n", progname
, loptstr ("|--ksk-rollover", ""));
452 sopt_usage ("\tusage: %s {-1} do.ma.in.\n", progname
);
453 lopt_usage ("\tusage: %s {--ksk-roll-phase1|--ksk-newkey} do.ma.in.\n", progname
);
454 sopt_usage ("\tusage: %s {-2} do.ma.in.\n", progname
);
455 lopt_usage ("\tusage: %s {--ksk-roll-phase2|--ksk-publish} do.ma.in.\n", progname
);
456 sopt_usage ("\tusage: %s {-3} do.ma.in.\n", progname
);
457 lopt_usage ("\tusage: %s {--ksk-roll-phase3|--ksk-delkey} do.ma.in.\n", progname
);
458 sopt_usage ("\tusage: %s {-0} do.ma.in.\n", progname
);
459 lopt_usage ("\tusage: %s {--ksk-roll-status|--ksk-status} do.ma.in.\n", progname
);
460 fprintf (stderr
, "\n");
462 fprintf (stderr
, "\n");
463 fprintf (stderr
, "General options \n");
464 fprintf (stderr
, "\t-c file%s", loptstr (", --config=file\n", ""));
465 fprintf (stderr
, "\t\t read config from <file> instead of %s\n", CONFIG_FILE
);
466 fprintf (stderr
, "\t-O optstr%s", loptstr (", --config-option=\"optstr\"\n", ""));
467 fprintf (stderr
, "\t\t read config options from commandline\n");
468 fprintf (stderr
, "\t-h%s\t no headline or trusted-key section header/trailer in -T mode\n", loptstr (", --nohead", "\t"));
469 fprintf (stderr
, "\t-d%s\t skip directory arguments\n", loptstr (", --directory", "\t"));
470 fprintf (stderr
, "\t-L%s\t print the domain name left justified (default: %s)\n", loptstr (", --leftjust", "\t"), ljustflag
? "on": "off");
471 fprintf (stderr
, "\t-l list\t\t print out only zone keys out of the given domain list\n");
472 fprintf (stderr
, "\t-p%s\t show path of keyfile / create key in current directory\n", loptstr (", --path", "\t"));
473 fprintf (stderr
, "\t-r%s\t recursive mode on/off (default: %s)\n", loptstr(", --recursive", "\t"), recflag
? "on": "off");
474 fprintf (stderr
, "\t-a%s\t print age of key (default: %s)\n", loptstr (", --age", "\t"), ageflag
? "on": "off");
475 fprintf (stderr
, "\t-t%s\t print key generation time (default: %s)\n", loptstr (", --time", "\t"),
476 timeflag
? "on": "off");
477 fprintf (stderr
, "\t-e%s\t print key expiration time\n", loptstr (", --expire", "\t"));
478 fprintf (stderr
, "\t-f%s\t print key lifetime\n", loptstr (", --lifetime", "\t"));
479 fprintf (stderr
, "\t-F days%s=days\t set key lifetime\n", loptstr (", --setlifetime", "\t"));
480 fprintf (stderr
, "\t-k%s\t key signing keys only\n", loptstr (", --ksk", "\t"));
481 fprintf (stderr
, "\t-z%s\t zone signing keys only\n", loptstr (", --zsk", "\t"));
483 fprintf (stderr
, "%s\n", mesg
);
487 static void createkey (const char *keyname
, const dki_t
*list
, const zconf_t
*conf
)
489 const char *dir
= "";
492 if ( keyname
== NULL
|| *keyname
== '\0' )
493 fatal ("Create key: no keyname!");
495 dbg_val2 ("createkey: keyname %s, pathflag = %d\n", keyname
, pathflag
);
496 /* search for already existent key to get the directory name */
497 if ( pathflag
&& (dkp
= (dki_t
*)zkt_search (list
, 0, keyname
)) != NULL
)
499 char path
[MAX_PATHSIZE
+1];
503 pathname (path
, sizeof (path
), dir
, LOCALCONF_FILE
, NULL
);
504 if ( fileexist (path
) ) /* load local config file */
506 dbg_val ("Load local config file \"%s\"\n", path
);
507 memcpy (&localconf
, conf
, sizeof (zconf_t
));
508 conf
= loadconfig (path
, &localconf
);
513 dkp
= dki_new (dir
, keyname
, DKI_ZSK
, conf
->k_algo
, conf
->z_bits
, conf
->z_random
, conf
->z_life
/ DAYSEC
);
515 dkp
= dki_new (dir
, keyname
, DKI_KSK
, conf
->k_algo
, conf
->k_bits
, conf
->k_random
, conf
->k_life
/ DAYSEC
);
517 fatal ("Can't create key %s: %s!\n", keyname
, dki_geterrstr ());
519 /* create a new key always in state published, which means "standby" for ksk */
520 dki_setstatus (dkp
, DKI_PUB
);
523 static int get_parent_phase (const char *file
)
528 if ( (fp
= fopen (file
, "r")) == NULL
)
532 if ( fscanf (fp
, "; KSK rollover phase%d", &phase
) != 1 )
539 static void ksk_roll (const char *keyname
, int phase
, const dki_t
*list
, const zconf_t
*conf
)
541 char path
[MAX_PATHSIZE
+1];
550 int parent_propagation
;
554 if ( phase
== 9 ) /* usage */
556 fprintf (stderr
, "A KSK rollover requires three consecutive steps:\n");
557 fprintf (stderr
, "\n");
558 fprintf (stderr
, "-1%s", loptstr ("|--ksk-roll-phase1 (--ksk-newkey)\n", ""));
559 fprintf (stderr
, "\t Create a new KSK.\n");
560 fprintf (stderr
, "\t This step also creates a parent-<domain> file which contains only\n");
561 fprintf (stderr
, "\t the _old_ key. This file will be copied in hierarchical mode\n");
562 fprintf (stderr
, "\t by dnssec-signer to the parent directory as keyset-<domain> file.\n");
563 fprintf (stderr
, "\t Wait until the new keyset is propagated, before going to the next step.\n");
564 fprintf (stderr
, "\n");
565 fprintf (stderr
, "-2%s", loptstr ("|--ksk-roll-phase2 (--ksk-publish)\n", ""));
566 fprintf (stderr
, "\t This step creates a parent-<domain> file with the _new_ key only.\n");
567 fprintf (stderr
, "\t Please send this file immediately to the parent (In hierarchical\n");
568 fprintf (stderr
, "\t mode this will be done automatically by the dnssec-signer command).\n");
569 fprintf (stderr
, "\t Then wait until the new DS is generated by the parent and propagated\n");
570 fprintf (stderr
, "\t to all the parent name server, plus the old DS TTL before going to step three.\n");
571 fprintf (stderr
, "\n");
572 fprintf (stderr
, "-3%s", loptstr ("|--ksk-roll-phase3 (--ksk-delkey)\n", ""));
573 fprintf (stderr
, "\t Remove (rename) the old KSK and the parent-<domain> file.\n");
574 fprintf (stderr
, "\t You have to manually delete the old KSK (look at file names beginning\n");
575 fprintf (stderr
, "\t with an lower 'k').\n");
576 fprintf (stderr
, "\n");
577 fprintf (stderr
, "-0%s", loptstr ("|--ksk-roll-stat (--ksk-status)\n", ""));
578 fprintf (stderr
, "\t Show the current KSK rollover state of a domain.\n");
580 fprintf (stderr
, "\n");
585 if ( keyname
== NULL
|| *keyname
== '\0' )
586 fatal ("ksk rollover: no domain!");
588 dbg_val2 ("ksk_roll: keyname %s, phase = %d\n", keyname
, phase
);
590 /* search for already existent key to get the directory name */
591 if ( (keylist
= (dki_t
*)zkt_search (list
, 0, keyname
)) == NULL
)
592 fatal ("ksk rollover: domain %s not found!\n", keyname
);
595 /* try to read local config file */
597 pathname (path
, sizeof (path
), dir
, LOCALCONF_FILE
, NULL
);
598 if ( fileexist (path
) ) /* load local config file */
600 dbg_val ("Load local config file \"%s\"\n", path
);
601 memcpy (&localconf
, conf
, sizeof (zconf_t
));
602 conf
= loadconfig (path
, &localconf
);
604 key_ttl
= conf
->key_ttl
;
606 /* check if parent-file already exist */
607 pathname (path
, sizeof (path
), dir
, "parent-", keyname
);
608 parent_phase
= parent_age
= 0;
609 if ( (parent_exist
= fileexist (path
)) != 0 )
611 parent_phase
= get_parent_phase (path
);
612 parent_age
= file_age (path
);
614 // parent_propagation = 2 * DAYSEC;
615 parent_propagation
= 5 * MINSEC
;
617 ksk
= 0; /* count active(!) key signing keys */
618 standby
= NULL
; /* find standby key if available */
619 for ( dkp
= keylist
; dkp
; dkp
= dkp
->next
)
620 if ( dki_isksk (dkp
) )
622 if ( dki_status (dkp
) == DKI_ACT
)
624 else if ( dki_status (dkp
) == DKI_PUB
)
630 case 0: /* print status (debug) */
631 fprintf (stdout
, "ksk_rollover:\n");
632 fprintf (stdout
, "\t domain = %s\n", keyname
);
633 fprintf (stdout
, "\t phase = %d\n", parent_phase
);
634 fprintf (stdout
, "\t parent_file %s %s\n", path
, parent_exist
? "exist": "not exist");
636 fprintf (stdout
, "\t age of parent_file %d %s\n", parent_age
, str_delspace (age2str (parent_age
)));
637 fprintf (stdout
, "\t # of active key signing keys %d\n", ksk
);
638 fprintf (stdout
, "\t parent_propagation %d %s\n", parent_propagation
, str_delspace (age2str (parent_propagation
)));
639 fprintf (stdout
, "\t keys ttl %d %s\n", key_ttl
, age2str (key_ttl
));
641 for ( dkp
= keylist
; dkp
; dkp
= dkp
->next
)
643 /* TODO: Nur zum testen */
644 dki_prt_dnskey (dkp
, stdout
);
648 if ( parent_exist
|| ksk
> 1 )
649 fatal ("Can\'t create new ksk because there is already an ksk rollover in progress\n");
651 fprintf (stdout
, "create new ksk \n");
652 dkp
= dki_new (dir
, keyname
, DKI_KSK
, conf
->k_algo
, conf
->k_bits
, conf
->k_random
, conf
->k_life
/ DAYSEC
);
654 fatal ("Can't create key %s: %s!\n", keyname
, dki_geterrstr ());
657 dki_setstatus (standby
, DKI_ACT
); /* activate standby key */
658 dki_setstatus (dkp
, DKI_PUB
); /* new key will be the new standby */
661 // dkp = keylist; /* use old key to create the parent file */
662 if ( (dkp
= (dki_t
*)dki_findalgo (keylist
, 1, conf
->k_algo
, 'a', 1)) == NULL
) /* find the oldest active ksk to create the parent file */
663 fatal ("ksk_rollover phase1: Couldn't find the old active key\n");
664 if ( !create_parent_file (path
, phase
, key_ttl
, dkp
) )
665 fatal ("Couldn't create parentfile %s\n", path
);
670 fatal ("Can\'t publish new key because no one exist\n");
672 fatal ("More than one KSK but no parent file found!\n");
673 if ( parent_phase
!= 1 )
674 fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase
);
675 if ( parent_age
< conf
->proptime
+ key_ttl
)
676 fatal ("ksk_rollover (phase2): you have to wait for the propagation of the new KSK (at least %dsec or %s)\n",
677 conf
->proptime
+ key_ttl
- parent_age
,
678 str_delspace (age2str (conf
->proptime
+ key_ttl
- parent_age
)));
680 fprintf (stdout
, "save new ksk in parent file\n");
681 dkp
= keylist
->next
; /* set dkp to new ksk */
682 if ( !create_parent_file (path
, phase
, key_ttl
, dkp
) )
683 fatal ("Couldn't create parentfile %s\n", path
);
686 if ( !parent_exist
|| ksk
< 2 )
687 fatal ("ksk-delkey only allowed after ksk-publish\n");
688 if ( parent_phase
!= 2 )
689 fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase
);
690 if ( parent_age
< parent_propagation
+ key_ttl
)
691 fatal ("ksk_rollover (phase3): you have to wait for DS propagation (at least %dsec or %s)\n",
692 parent_propagation
+ key_ttl
- parent_age
,
693 str_delspace (age2str (parent_propagation
+ key_ttl
- parent_age
)));
694 /* remove the parentfile */
695 fprintf (stdout
, "remove parentfile \n");
697 /* remove or rename the old key */
698 fprintf (stdout
, "old ksk renamed \n");
699 dkp
= keylist
; /* set dkp to old ksk */
702 default: assert (phase
== 1 || phase
== 2 || phase
== 3);
706 /*****************************************************************
707 ** create_parent_file ()
708 *****************************************************************/
709 static int create_parent_file (const char *fname
, int phase
, int ttl
, const dki_t
*dkp
)
713 assert ( fname
!= NULL
);
715 if ( dkp
== NULL
|| (phase
!= 1 && phase
!= 2) )
718 if ( (fp
= fopen (fname
, "w")) == NULL
)
719 fatal ("can\'t create new parentfile \"%s\"\n", fname
);
722 fprintf (fp
, "; KSK rollover phase1 (old key)\n");
724 fprintf (fp
, "; KSK rollover phase2 (new key)\n");
726 dki_prt_dnskeyttl (dkp
, fp
, ttl
);
732 static int parsedirectory (const char *dir
, dki_t
**listp
)
736 struct dirent
*dentp
;
737 char path
[MAX_PATHSIZE
+1];
742 dbg_val ("directory: opendir(%s)\n", dir
);
743 if ( (dirp
= opendir (dir
)) == NULL
)
746 while ( (dentp
= readdir (dirp
)) != NULL
)
748 if ( is_dotfilename (dentp
->d_name
) )
751 dbg_val ("directory: check %s\n", dentp
->d_name
);
752 pathname (path
, sizeof (path
), dir
, dentp
->d_name
, NULL
);
753 if ( is_directory (path
) && recflag
)
755 dbg_val ("directory: recursive %s\n", path
);
756 parsedirectory (path
, listp
);
758 else if ( is_keyfilename (dentp
->d_name
) )
759 if ( (dkp
= dki_read (dir
, dentp
->d_name
)) )
761 // fprintf (stderr, "parsedir: tssearch (%d %s)\n", dkp, dkp->name);
762 #if defined (USE_TREE) && USE_TREE
763 dki_tadd (listp
, dkp
);
765 dki_add (listp
, dkp
);
773 static void parsefile (const char *file
, dki_t
**listp
)
775 char path
[MAX_PATHSIZE
+1];
778 /* file arg contains path ? ... */
779 file
= splitpath (path
, sizeof (path
), file
); /* ... then split of */
781 if ( is_keyfilename (file
) ) /* plain file name looks like DNS key file ? */
783 if ( (dkp
= dki_read (path
, file
)) ) /* read DNS key file ... */
784 #if defined (USE_TREE) && USE_TREE
785 dki_tadd (listp
, dkp
); /* ... and add to tree */
787 dki_add (listp
, dkp
); /* ... and add to list */
790 error ("error parsing %s: (%s)\n", file
, dki_geterrstr());
794 static const char *parsetag (const char *str
, int *tagp
)
799 while ( isspace (*str
) ) /* skip leading ws */
803 if ( isdigit (*p
) ) /* keytag starts with digit */
805 sscanf (p
, "%u", tagp
); /* read keytag as number */
806 do /* eat up to the end of the number */
808 while ( isdigit (*p
) );
810 if ( *p
== ':' ) /* label follows ? */
811 return p
+1; /* return that */
813 return NULL
; /* no label */
815 return str
; /* return as label string if not a numeric keytag */