1/***************************************************************** 2** 3** @(#) zkt-keyman.c (c) Jan 2005 - Apr 2010 Holger Zuleger hznet.de 4** 5** ZKT key managing tool (formely knon as dnsses-zkt) 6** A wrapper command around the BIND dnssec-keygen utility 7** 8** Copyright (c) 2005 - 2010, Holger Zuleger HZnet. All rights reserved. 9** 10** This software is open source. 11** 12** Redistribution and use in source and binary forms, with or without 13** modification, are permitted provided that the following conditions 14** are met: 15** 16** Redistributions of source code must retain the above copyright notice, 17** this list of conditions and the following disclaimer. 18** 19** Redistributions in binary form must reproduce the above copyright notice, 20** this list of conditions and the following disclaimer in the documentation 21** and/or other materials provided with the distribution. 22** 23** Neither the name of Holger Zuleger HZnet nor the names of its contributors may 24** be used to endorse or promote products derived from this software without 25** specific prior written permission. 26** 27** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 31** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37** POSSIBILITY OF SUCH DAMAGE. 38** 39*****************************************************************/ 40 41# include <stdio.h> 42# include <stdlib.h> /* abort(), exit(), ... */ 43# include <string.h> 44# include <dirent.h> 45# include <assert.h> 46# include <unistd.h> 47# include <ctype.h> 48 49#ifdef HAVE_CONFIG_H 50# include <config.h> 51#endif 52# include "config_zkt.h" 53#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG 54# include <getopt.h> 55#endif 56 57# include "debug.h" 58# include "misc.h" 59# include "strlist.h" 60# include "zconf.h" 61# include "dki.h" 62# include "zkt.h" 63 64extern int optopt; 65extern int opterr; 66extern int optind; 67extern char *optarg; 68const char *progname; 69 70char *labellist = NULL; 71 72int headerflag = 1; 73int ageflag = 0; 74int lifetime = 0; 75int lifetimeflag = 0; 76int timeflag = 1; 77int exptimeflag = 0; 78int pathflag = 0; 79int kskflag = 1; 80int zskflag = 1; 81int ljustflag = 0; 82 83static int dirflag = 0; 84static int recflag = RECURSIVE; 85static char *kskdomain = ""; 86static const char *view = ""; 87 88# define short_options ":0:1:2:3:9A:C:D:P:S:R:h:ZV:F:c:O:krz" 89#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG 90static struct option long_options[] = { 91 {"ksk-rollover", no_argument, NULL, '9'}, 92 {"ksk-status", required_argument, NULL, '0'}, 93 {"ksk-roll-status", required_argument, NULL, '0'}, 94 {"ksk-newkey", required_argument, NULL, '1'}, 95 {"ksk-publish", required_argument, NULL, '2'}, 96 {"ksk-delkey", required_argument, NULL, '3'}, 97 {"ksk-roll-phase1", required_argument, NULL, '1'}, 98 {"ksk-roll-phase2", required_argument, NULL, '2'}, 99 {"ksk-roll-phase3", required_argument, NULL, '3'}, 100 {"ksk", no_argument, NULL, 'k'}, 101 {"zsk", no_argument, NULL, 'z'}, 102 {"recursive", no_argument, NULL, 'r'}, 103 {"config", required_argument, NULL, 'c'}, 104 {"option", required_argument, NULL, 'O'}, 105 {"config-option", required_argument, NULL, 'O'}, 106 {"published", required_argument, NULL, 'P'}, 107 {"standby", required_argument, NULL, 'S'}, 108 {"active", required_argument, NULL, 'A'}, 109 {"depreciated", required_argument, NULL, 'D'}, 110 {"create", required_argument, NULL, 'C'}, 111 {"revoke", required_argument, NULL, 'R'}, 112 {"remove", required_argument, NULL, 19 }, 113 {"destroy", required_argument, NULL, 20 }, 114 {"setlifetime", required_argument, NULL, 'F' }, 115 {"view", required_argument, NULL, 'V' }, 116 {"help", no_argument, NULL, 'h'}, 117 {0, 0, 0, 0} 118}; 119#endif 120 121static int parsedirectory (const char *dir, dki_t **listp); 122static void parsefile (const char *file, dki_t **listp); 123static void createkey (const char *keyname, const dki_t *list, const zconf_t *conf); 124static void ksk_roll (const char *keyname, int phase, const dki_t *list, const zconf_t *conf); 125static int create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp); 126static void usage (char *mesg, zconf_t *cp); 127static const char *parsetag (const char *str, int *tagp); 128 129static void setglobalflags (zconf_t *config) 130{ 131 recflag = config->recursive; 132} 133 134int main (int argc, char *argv[]) 135{ 136 dki_t *data = NULL; 137 dki_t *dkp; 138 int c; 139 int opt_index; 140 int action; 141 const char *file; 142 const char *defconfname = NULL; 143 char *p; 144 char str[254+1]; 145 const char *keyname = NULL; 146 int searchtag; 147 zconf_t *config; 148 149 progname = *argv; 150 if ( (p = strrchr (progname, '/')) ) 151 progname = ++p; 152 view = getnameappendix (progname, "dnssec-zkt"); 153 154 defconfname = getdefconfname (view); 155 config = loadconfig ("", (zconf_t *)NULL); /* load built in config */ 156 if ( fileexist (defconfname) ) /* load default config file */ 157 config = loadconfig (defconfname, config); 158 if ( config == NULL ) 159 fatal ("Out of memory\n"); 160 setglobalflags (config); 161 162 opterr = 0; 163 opt_index = 0; 164 action = 0; 165#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG 166 while ( (c = getopt_long (argc, argv, short_options, long_options, &opt_index)) != -1 ) 167#else 168 while ( (c = getopt (argc, argv, short_options)) != -1 ) 169#endif 170 { 171 switch ( c ) 172 { 173 case '9': /* ksk rollover help */ 174 ksk_roll ("help", c - '0', NULL, NULL); 175 exit (1); 176 case '1': /* ksk rollover: create new key */ 177 case '2': /* ksk rollover: publish DS */ 178 case '3': /* ksk rollover: delete old key */ 179 case '0': /* ksk rollover: show current status */ 180 action = c; 181 if ( !optarg ) 182 usage ("ksk rollover requires an domain argument", config); 183 kskdomain = domain_canonicdup (optarg); 184 break; 185 case 'h': 186 case 'K': 187 case 'Z': 188 action = c; 189 break; 190 case 'C': 191 pathflag = !pathflag; 192 /* fall through */ 193 case 'P': 194 case 'S': 195 case 'A': 196 case 'D': 197 case 'R': 198 case 's': 199 case 19: 200 case 20: 201 if ( (keyname = parsetag (optarg, &searchtag)) != NULL ) 202 keyname = domain_canonicdup (keyname); 203 action = c; 204 break; 205 case 'F': /* set key lifetime */ 206 lifetime = atoi (optarg); 207 action = c; 208 break; 209 case 'V': /* view name */ 210 view = optarg; 211 defconfname = getdefconfname (view); 212 if ( fileexist (defconfname) ) /* load default config file */ 213 config = loadconfig (defconfname, config); 214 if ( config == NULL ) 215 fatal ("Out of memory\n"); 216 setglobalflags (config); 217 break; 218 case 'c': 219 config = loadconfig (optarg, config); 220 setglobalflags (config); 221 checkconfig (config); 222 break; 223 case 'O': /* read option from commandline */ 224 config = loadconfig_fromstr (optarg, config); 225 setglobalflags (config); 226 checkconfig (config); 227 break; 228 case 'd': /* ignore directory arg */ 229 dirflag = 1; 230 break; 231 case 'k': /* ksk only */ 232 zskflag = 0; 233 break; 234 case 'r': /* switch recursive flag */ 235 recflag = !recflag; 236 break; 237 case 'z': /* zsk only */ 238 kskflag = 0; 239 break; 240 case ':': 241 snprintf (str, sizeof(str), "option \"-%c\" requires an argument.\n", 242 optopt); 243 usage (str, config); 244 break; 245 case '?': 246 if ( isprint (optopt) ) 247 snprintf (str, sizeof(str), "Unknown option \"-%c\".\n", 248 optopt); 249 else 250 snprintf (str, sizeof (str), "Unknown option char \\x%x.\n", 251 optopt); 252 usage (str, config); 253 break; 254 default: 255 abort(); 256 } 257 } 258 259 if ( kskflag == 0 && zskflag == 0 ) 260 kskflag = zskflag = 1; 261 262 c = optind; 263 do { 264 if ( c >= argc ) /* no args left */ 265 file = config->zonedir; /* use default directory */ 266 else 267 file = argv[c++]; 268 269 if ( is_directory (file) ) 270 parsedirectory (file, &data); 271 else 272 parsefile (file, &data); 273 274 } while ( c < argc ); /* for all arguments */ 275 276 switch ( action ) 277 { 278 case 'h': 279 usage ("", config); 280 case 'C': 281 createkey (keyname, data, config); 282 break; 283 case 'P': 284 case 'S': 285 case 'A': 286 case 'D': 287 if ( (dkp = (dki_t*)zkt_search (data, searchtag, keyname)) == NULL ) 288 fatal ("Key with tag %u not found\n", searchtag); 289 else if ( dkp == (void *) 01 ) 290 fatal ("Key with tag %u found multiple times\n", searchtag); 291 if ( (c = dki_setstatus_preservetime (dkp, action)) != 0 ) 292 fatal ("Couldn't change status of key %u: %d\n", searchtag, c); 293 break; 294 case 19: /* remove (rename) key file */ 295 if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL ) 296 fatal ("Key with tag %u not found\n", searchtag); 297 else if ( dkp == (void *) 01 ) 298 fatal ("Key with tag %u found multiple times\n", searchtag); 299 dki_remove (dkp); 300 break; 301 case 20: /* destroy the key (remove the files!) */ 302 if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL ) 303 fatal ("Key with tag %u not found\n", searchtag); 304 else if ( dkp == (void *) 01 ) 305 fatal ("Key with tag %u found multiple times\n", searchtag); 306 dki_destroy (dkp); 307 break; 308 case 'R': 309 if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL ) 310 fatal ("Key with tag %u not found\n", searchtag); 311 else if ( dkp == (void *) 01 ) 312 fatal ("Key with tag %u found multiple times\n", searchtag); 313 if ( (c = dki_setstatus (dkp, action)) != 0 ) 314 fatal ("Couldn't change status of key %u: %d\n", searchtag, c); 315 break; 316 case '1': /* ksk rollover new key */ 317 case '2': /* ksk rollover publish DS */ 318 case '3': /* ksk rollover delete old key */ 319 case '0': /* ksk rollover status */ 320 ksk_roll (kskdomain, action - '0', data, config); 321 break; 322 case 'F': 323 zkt_setkeylifetime (data); 324 /* fall through */ 325 default: 326 zkt_list_keys (data); 327 } 328 329 return 0; 330} 331 332# define sopt_usage(mesg, value) fprintf (stderr, mesg, value) 333#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG 334# define lopt_usage(mesg, value) fprintf (stderr, mesg, value) 335# define loptstr(lstr, sstr) lstr 336#else 337# define lopt_usage(mesg, value) 338# define loptstr(lstr, sstr) sstr 339#endif 340static void usage (char *mesg, zconf_t *cp) 341{ 342 fprintf (stderr, "DNS Zone Key Management Tool %s\n", ZKT_VERSION); 343 fprintf (stderr, "\n"); 344 fprintf (stderr, "Create a new key \n"); 345 sopt_usage ("\tusage: %s -C <name> [-k] [-dpr] [-c config] [dir ...]\n", progname); 346 lopt_usage ("\tusage: %s --create=<name> [-k] [-dpr] [-c config] [dir ...]\n", progname); 347 fprintf (stderr, "\t\tKSK (use -k): %s %d bits\n", dki_algo2str (cp->k_algo), cp->k_bits); 348 fprintf (stderr, "\t\tZSK (default): %s %d bits\n", dki_algo2str (cp->k_algo), cp->z_bits); 349 fprintf (stderr, "\n"); 350 fprintf (stderr, "Change key status of specified key to published, active or depreciated\n"); 351 fprintf (stderr, "\t(<keyspec> := tag | tag:name) \n"); 352 sopt_usage ("\tusage: %s -P|-A|-D <keyspec> [-dr] [-c config] [dir ...]\n", progname); 353 lopt_usage ("\tusage: %s --published=<keyspec> [-dr] [-c config] [dir ...]\n", progname); 354 lopt_usage ("\tusage: %s --active=<keyspec> [-dr] [-c config] [dir ...]\n", progname); 355 lopt_usage ("\tusage: %s --depreciated=<keyspec> [-dr] [-c config] [dir ...]\n", progname); 356 fprintf (stderr, "\n"); 357 fprintf (stderr, "Revoke specified key (<keyspec> := tag | tag:name) \n"); 358 sopt_usage ("\tusage: %s -R <keyspec> [-dr] [-c config] [dir ...]\n", progname); 359 lopt_usage ("\tusage: %s --revoke=<keyspec> [-dr] [-c config] [dir ...]\n", progname); 360 fprintf (stderr, "\n"); 361 fprintf (stderr, "Remove (rename) or destroy (delete) specified key (<keyspec> := tag | tag:name) \n"); 362 lopt_usage ("\tusage: %s --remove=<keyspec> [-dr] [-c config] [dir ...]\n", progname); 363 lopt_usage ("\tusage: %s --destroy=<keyspec> [-dr] [-c config] [dir ...]\n", progname); 364 fprintf (stderr, "\n"); 365 fprintf (stderr, "Initiate a semi-automated KSK rollover"); 366 fprintf (stderr, "('%s -9%s' prints out a brief description)\n", progname, loptstr ("|--ksk-rollover", "")); 367 sopt_usage ("\tusage: %s {-1} do.ma.in.\n", progname); 368 lopt_usage ("\tusage: %s {--ksk-roll-phase1|--ksk-newkey} do.ma.in.\n", progname); 369 sopt_usage ("\tusage: %s {-2} do.ma.in.\n", progname); 370 lopt_usage ("\tusage: %s {--ksk-roll-phase2|--ksk-publish} do.ma.in.\n", progname); 371 sopt_usage ("\tusage: %s {-3} do.ma.in.\n", progname); 372 lopt_usage ("\tusage: %s {--ksk-roll-phase3|--ksk-delkey} do.ma.in.\n", progname); 373 sopt_usage ("\tusage: %s {-0} do.ma.in.\n", progname); 374 lopt_usage ("\tusage: %s {--ksk-roll-status|--ksk-status} do.ma.in.\n", progname); 375 fprintf (stderr, "\n"); 376 377 fprintf (stderr, "\n"); 378 fprintf (stderr, "General options \n"); 379 fprintf (stderr, "\t-c file%s", loptstr (", --config=file\n", "")); 380 fprintf (stderr, "\t\t read config from <file> instead of %s\n", CONFIG_FILE); 381 fprintf (stderr, "\t-O optstr%s", loptstr (", --config-option=\"optstr\"\n", "")); 382 fprintf (stderr, "\t\t read config options from commandline\n"); 383 fprintf (stderr, "\t-d%s\t skip directory arguments\n", loptstr (", --directory", "\t")); 384 fprintf (stderr, "\t-r%s\t recursive mode on/off (default: %s)\n", loptstr(", --recursive", "\t"), recflag ? "on": "off"); 385 fprintf (stderr, "\t-F days%s=days\t set key lifetime\n", loptstr (", --setlifetime", "\t")); 386 fprintf (stderr, "\t-k%s\t key signing keys only\n", loptstr (", --ksk", "\t")); 387 fprintf (stderr, "\t-z%s\t zone signing keys only\n", loptstr (", --zsk", "\t")); 388 if ( mesg && *mesg ) 389 fprintf (stderr, "%s\n", mesg); 390 exit (1); 391} 392 393static void createkey (const char *keyname, const dki_t *list, const zconf_t *conf) 394{ 395 const char *dir = ""; 396 dki_t *dkp; 397 398 if ( keyname == NULL || *keyname == '\0' ) 399 fatal ("Create key: no keyname!"); 400 401 dbg_val2 ("createkey: keyname %s, pathflag = %d\n", keyname, pathflag); 402 /* search for already existent key to get the directory name */ 403 if ( pathflag && (dkp = (dki_t *)zkt_search (list, 0, keyname)) != NULL ) 404 { 405 char path[MAX_PATHSIZE+1]; 406 zconf_t localconf; 407 408 dir = dkp->dname; 409 pathname (path, sizeof (path), dir, LOCALCONF_FILE, NULL); 410 if ( fileexist (path) ) /* load local config file */ 411 { 412 dbg_val ("Load local config file \"%s\"\n", path); 413 memcpy (&localconf, conf, sizeof (zconf_t)); 414 conf = loadconfig (path, &localconf); 415 } 416 } 417 418 if ( zskflag ) 419 dkp = dki_new (dir, keyname, DKI_ZSK, conf->k_algo, conf->z_bits, conf->z_random, conf->z_life / DAYSEC); 420 else 421 dkp = dki_new (dir, keyname, DKI_KSK, conf->k_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC); 422 if ( dkp == NULL ) 423 fatal ("Can't create key %s: %s!\n", keyname, dki_geterrstr ()); 424 425 /* create a new key always in state published, which means "standby" for ksk */ 426 dki_setstatus (dkp, DKI_PUB); 427} 428 429static int get_parent_phase (const char *file) 430{ 431 FILE *fp; 432 int phase; 433 434 if ( (fp = fopen (file, "r")) == NULL ) 435 return -1; 436 437 phase = 0; 438 if ( fscanf (fp, "; KSK rollover phase%d", &phase) != 1 ) 439 phase = 0; 440 441 fclose (fp); 442 return phase; 443} 444 445static void ksk_roll (const char *keyname, int phase, const dki_t *list, const zconf_t *conf) 446{ 447 char path[MAX_PATHSIZE+1]; 448 zconf_t localconf; 449 const char *dir; 450 dki_t *keylist; 451 dki_t *dkp; 452 dki_t *standby; 453 int parent_exist; 454 int parent_age; 455 int parent_phase; 456 int parent_propagation; 457 int key_ttl; 458 int ksk; 459 460 if ( phase == 9 ) /* usage */ 461 { 462 fprintf (stderr, "A KSK rollover requires three consecutive steps:\n"); 463 fprintf (stderr, "\n"); 464 fprintf (stderr, "-1%s", loptstr ("|--ksk-roll-phase1 (--ksk-newkey)\n", "")); 465 fprintf (stderr, "\t Create a new KSK.\n"); 466 fprintf (stderr, "\t This step also creates a parent-<domain> file which contains only\n"); 467 fprintf (stderr, "\t the _old_ key. This file will be copied in hierarchical mode\n"); 468 fprintf (stderr, "\t by dnssec-signer to the parent directory as keyset-<domain> file.\n"); 469 fprintf (stderr, "\t Wait until the new keyset is propagated, before going to the next step.\n"); 470 fprintf (stderr, "\n"); 471 fprintf (stderr, "-2%s", loptstr ("|--ksk-roll-phase2 (--ksk-publish)\n", "")); 472 fprintf (stderr, "\t This step creates a parent-<domain> file with the _new_ key only.\n"); 473 fprintf (stderr, "\t Please send this file immediately to the parent (In hierarchical\n"); 474 fprintf (stderr, "\t mode this will be done automatically by the dnssec-signer command).\n"); 475 fprintf (stderr, "\t Then wait until the new DS is generated by the parent and propagated\n"); 476 fprintf (stderr, "\t to all the parent name server, plus the old DS TTL before going to step three.\n"); 477 fprintf (stderr, "\n"); 478 fprintf (stderr, "-3%s", loptstr ("|--ksk-roll-phase3 (--ksk-delkey)\n", "")); 479 fprintf (stderr, "\t Remove (rename) the old KSK and the parent-<domain> file.\n"); 480 fprintf (stderr, "\t You have to manually delete the old KSK (look at file names beginning\n"); 481 fprintf (stderr, "\t with an lower 'k').\n"); 482 fprintf (stderr, "\n"); 483 fprintf (stderr, "-0%s", loptstr ("|--ksk-roll-stat (--ksk-status)\n", "")); 484 fprintf (stderr, "\t Show the current KSK rollover state of a domain.\n"); 485 486 fprintf (stderr, "\n"); 487 488 return; 489 } 490 491 if ( keyname == NULL || *keyname == '\0' ) 492 fatal ("ksk rollover: no domain!"); 493 494 dbg_val2 ("ksk_roll: keyname %s, phase = %d\n", keyname, phase); 495 496 /* search for already existent key to get the directory name */ 497 if ( (keylist = (dki_t *)zkt_search (list, 0, keyname)) == NULL ) 498 fatal ("ksk rollover: domain %s not found!\n", keyname); 499 dkp = keylist; 500 501 /* try to read local config file */ 502 dir = dkp->dname; 503 pathname (path, sizeof (path), dir, LOCALCONF_FILE, NULL); 504 if ( fileexist (path) ) /* load local config file */ 505 { 506 dbg_val ("Load local config file \"%s\"\n", path); 507 memcpy (&localconf, conf, sizeof (zconf_t)); 508 conf = loadconfig (path, &localconf); 509 } 510 key_ttl = conf->key_ttl; 511 512 /* check if parent-file already exist */ 513 pathname (path, sizeof (path), dir, "parent-", keyname); 514 parent_phase = parent_age = 0; 515 if ( (parent_exist = fileexist (path)) != 0 ) 516 { 517 parent_phase = get_parent_phase (path); 518 parent_age = file_age (path); 519 } 520 // parent_propagation = 2 * DAYSEC; 521 parent_propagation = 5 * MINSEC; 522 523 ksk = 0; /* count active(!) key signing keys */ 524 standby = NULL; /* find standby key if available */ 525 for ( dkp = keylist; dkp; dkp = dkp->next ) 526 if ( dki_isksk (dkp) ) 527 { 528 if ( dki_status (dkp) == DKI_ACT ) 529 ksk++; 530 else if ( dki_status (dkp) == DKI_PUB ) 531 standby = dkp; 532 } 533 534 switch ( phase ) 535 { 536 case 0: /* print status (debug) */ 537 fprintf (stdout, "ksk_rollover:\n"); 538 fprintf (stdout, "\t domain = %s\n", keyname); 539 fprintf (stdout, "\t phase = %d\n", parent_phase); 540 fprintf (stdout, "\t parent_file %s %s\n", path, parent_exist ? "exist": "not exist"); 541 if ( parent_exist ) 542 fprintf (stdout, "\t age of parent_file %d %s\n", parent_age, str_delspace (age2str (parent_age))); 543 fprintf (stdout, "\t # of active key signing keys %d\n", ksk); 544 fprintf (stdout, "\t parent_propagation %d %s\n", parent_propagation, str_delspace (age2str (parent_propagation))); 545 fprintf (stdout, "\t keys ttl %d %s\n", key_ttl, age2str (key_ttl)); 546 547 for ( dkp = keylist; dkp; dkp = dkp->next ) 548 { 549 /* TODO: Nur zum testen */ 550 dki_prt_dnskey (dkp, stdout); 551 } 552 break; 553 case 1: 554 if ( parent_exist || ksk > 1 ) 555 fatal ("Can\'t create new ksk because there is already an ksk rollover in progress\n"); 556 557 fprintf (stdout, "create new ksk \n"); 558 dkp = dki_new (dir, keyname, DKI_KSK, conf->k_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC); 559 if ( dkp == NULL ) 560 fatal ("Can't create key %s: %s!\n", keyname, dki_geterrstr ()); 561 if ( standby ) 562 { 563 dki_setstatus (standby, DKI_ACT); /* activate standby key */ 564 dki_setstatus (dkp, DKI_PUB); /* new key will be the new standby */ 565 } 566 567 // dkp = keylist; /* use old key to create the parent file */ 568 if ( (dkp = (dki_t *)dki_findalgo (keylist, 1, conf->k_algo, 'a', 1)) == NULL ) /* find the oldest active ksk to create the parent file */ 569 fatal ("ksk_rollover phase1: Couldn't find the old active key\n"); 570 if ( !create_parent_file (path, phase, key_ttl, dkp) ) 571 fatal ("Couldn't create parentfile %s\n", path); 572 break; 573 574 case 2: 575 if ( ksk < 2 ) 576 fatal ("Can\'t publish new key because no one exist\n"); 577 if ( !parent_exist ) 578 fatal ("More than one KSK but no parent file found!\n"); 579 if ( parent_phase != 1 ) 580 fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase); 581 if ( parent_age < conf->proptime + key_ttl ) 582 fatal ("ksk_rollover (phase2): you have to wait for the propagation of the new KSK (at least %dsec or %s)\n", 583 conf->proptime + key_ttl - parent_age, 584 str_delspace (age2str (conf->proptime + key_ttl - parent_age))); 585 586 fprintf (stdout, "save new ksk in parent file\n"); 587 dkp = keylist->next; /* set dkp to new ksk */ 588 if ( !create_parent_file (path, phase, key_ttl, dkp) ) 589 fatal ("Couldn't create parentfile %s\n", path); 590 break; 591 case 3: 592 if ( !parent_exist || ksk < 2 ) 593 fatal ("ksk-delkey only allowed after ksk-publish\n"); 594 if ( parent_phase != 2 ) 595 fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase); 596 if ( parent_age < parent_propagation + key_ttl ) 597 fatal ("ksk_rollover (phase3): you have to wait for DS propagation (at least %dsec or %s)\n", 598 parent_propagation + key_ttl - parent_age, 599 str_delspace (age2str (parent_propagation + key_ttl - parent_age))); 600 /* remove the parentfile */ 601 fprintf (stdout, "remove parentfile \n"); 602 unlink (path); 603 /* remove or rename the old key */ 604 fprintf (stdout, "old ksk renamed \n"); 605 dkp = keylist; /* set dkp to old ksk */ 606 dki_remove (dkp); 607 break; 608 default: assert (phase == 1 || phase == 2 || phase == 3); 609 } 610} 611 612/***************************************************************** 613** create_parent_file () 614*****************************************************************/ 615static int create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp) 616{ 617 FILE *fp; 618 619 assert ( fname != NULL ); 620 621 if ( dkp == NULL || (phase != 1 && phase != 2) ) 622 return 0; 623 624 if ( (fp = fopen (fname, "w")) == NULL ) 625 fatal ("can\'t create new parentfile \"%s\"\n", fname); 626 627 if ( phase == 1 ) 628 fprintf (fp, "; KSK rollover phase1 (old key)\n"); 629 else 630 fprintf (fp, "; KSK rollover phase2 (new key)\n"); 631 632 dki_prt_dnskeyttl (dkp, fp, ttl); 633 fclose (fp); 634 635 return phase; 636} 637 638static int parsedirectory (const char *dir, dki_t **listp) 639{ 640 dki_t *dkp; 641 DIR *dirp; 642 struct dirent *dentp; 643 char path[MAX_PATHSIZE+1]; 644 645 if ( dirflag ) 646 return 0; 647 648 dbg_val ("directory: opendir(%s)\n", dir); 649 if ( (dirp = opendir (dir)) == NULL ) 650 return 0; 651 652 while ( (dentp = readdir (dirp)) != NULL ) 653 { 654 if ( is_dotfilename (dentp->d_name) ) 655 continue; 656 657 dbg_val ("directory: check %s\n", dentp->d_name); 658 pathname (path, sizeof (path), dir, dentp->d_name, NULL); 659 if ( is_directory (path) && recflag ) 660 { 661 dbg_val ("directory: recursive %s\n", path); 662 parsedirectory (path, listp); 663 } 664 else if ( is_keyfilename (dentp->d_name) ) 665 if ( (dkp = dki_read (dir, dentp->d_name)) ) 666 { 667 // fprintf (stderr, "parsedir: tssearch (%d %s)\n", dkp, dkp->name); 668#if defined (USE_TREE) && USE_TREE 669 dki_tadd (listp, dkp, 1); 670#else 671 dki_add (listp, dkp); 672#endif 673 } 674 } 675 closedir (dirp); 676 return 1; 677} 678 679static void parsefile (const char *file, dki_t **listp) 680{ 681 char path[MAX_PATHSIZE+1]; 682 dki_t *dkp; 683 684 /* file arg contains path ? ... */ 685 file = splitpath (path, sizeof (path), file); /* ... then split of */ 686 687 if ( is_keyfilename (file) ) /* plain file name looks like DNS key file ? */ 688 { 689 if ( (dkp = dki_read (path, file)) ) /* read DNS key file ... */ 690#if defined (USE_TREE) && USE_TREE 691 dki_tadd (listp, dkp, 1); /* ... and add to tree */ 692#else 693 dki_add (listp, dkp); /* ... and add to list */ 694#endif 695 else 696 error ("error parsing %s: (%s)\n", file, dki_geterrstr()); 697 } 698} 699 700static const char *parsetag (const char *str, int *tagp) 701{ 702 const char *p; 703 704 *tagp = 0; 705 while ( isspace (*str) ) /* skip leading ws */ 706 str++; 707 708 p = str; 709 if ( isdigit (*p) ) /* keytag starts with digit */ 710 { 711 sscanf (p, "%u", tagp); /* read keytag as number */ 712 do /* eat up to the end of the number */ 713 p++; 714 while ( isdigit (*p) ); 715 716 if ( *p == ':' ) /* label follows ? */ 717 return p+1; /* return that */ 718 if ( *p == '\0' ) 719 return NULL; /* no label */ 720 } 721 return str; /* return as label string if not a numeric keytag */ 722} 723