1/***************************************************************** 2** 3** @(#) rollover.c -- The key rollover functions 4** 5** Copyright (c) Jan 2005 - May 2008, Holger Zuleger HZnet. All rights reserved. 6** 7** This software is open source. 8** 9** Redistribution and use in source and binary forms, with or without 10** modification, are permitted provided that the following conditions 11** are met: 12** 13** Redistributions of source code must retain the above copyright notice, 14** this list of conditions and the following disclaimer. 15** 16** Redistributions in binary form must reproduce the above copyright notice, 17** this list of conditions and the following disclaimer in the documentation 18** and/or other materials provided with the distribution. 19** 20** Neither the name of Holger Zuleger HZnet nor the names of its contributors may 21** be used to endorse or promote products derived from this software without 22** specific prior written permission. 23** 24** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 28** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34** POSSIBILITY OF SUCH DAMAGE. 35** 36*****************************************************************/ 37# include <stdio.h> 38# include <string.h> 39# include <stdlib.h> 40# include <ctype.h> 41# include <time.h> 42# include <assert.h> 43# include <dirent.h> 44# include <errno.h> 45# include <unistd.h> 46#ifdef HAVE_CONFIG_H 47# include <config.h> 48#endif 49# include "config_zkt.h" 50# include "zconf.h" 51# include "debug.h" 52 53# include "misc.h" 54# include "zone.h" 55# include "dki.h" 56# include "log.h" 57#define extern 58# include "rollover.h" 59#undef extern 60 61/***************************************************************** 62** local function definition 63*****************************************************************/ 64 65static dki_t *genkey (dki_t **listp, const char *dir, const char *domain, int ksk, const zconf_t *conf, int status) 66{ 67 dki_t *dkp; 68 69 if ( listp == NULL || domain == NULL ) 70 return NULL; 71 72 if ( ksk ) 73 dkp = dki_new (dir, domain, DKI_KSK, conf->k_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC); 74 else 75 dkp = dki_new (dir, domain, DKI_ZSK, conf->k_algo, conf->z_bits, conf->z_random, conf->z_life / DAYSEC); 76 dki_add (listp, dkp); 77 dki_setstatus (dkp, status); 78 79 return dkp; 80} 81 82static dki_t *genkey2 (dki_t **listp, const char *dir, const char *domain, int ksk, const zconf_t *conf, int status) 83{ 84 dki_t *dkp; 85 86 if ( listp == NULL || domain == NULL ) 87 return NULL; 88 89 if ( ksk ) 90 dkp = dki_new (dir, domain, DKI_KSK, conf->k2_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC); 91 else 92 dkp = dki_new (dir, domain, DKI_ZSK, conf->k2_algo, conf->z_bits, conf->z_random, conf->z_life / DAYSEC); 93 dki_add (listp, dkp); 94 dki_setstatus (dkp, status); 95 96 return dkp; 97} 98 99static time_t get_exptime (dki_t *key, const zconf_t *z) 100{ 101 time_t exptime; 102 103 exptime = dki_exptime (key); 104 if ( exptime == 0L ) 105 { 106 if ( dki_lifetime (key) ) 107 exptime = dki_time (key) + dki_lifetime (key); 108 else 109 exptime = dki_time (key) + z->k_life; 110 } 111 112 return exptime; 113} 114 115/***************************************************************** 116** is_parentdirsigned (name) 117** Check if the parent directory of the zone specified by zp 118** is a directory with a signed zone 119** Returns 0 | 1 120*****************************************************************/ 121static int is_parentdirsigned (const zone_t *zonelist, const zone_t *zp) 122{ 123 char path[MAX_PATHSIZE+1]; 124 const char *ext; 125#if 0 126 const zconf_t *conf; 127 128 /* check if there is a local config file to get the name of the zone file */ 129 snprintf (path, sizeof (path), "%s/../%s", zp->dir, LOCALCONF_FILE); 130 if ( fileexist (path) ) /* parent dir has local config file ? */ 131 conf = loadconfig (path, NULL); 132 else 133 conf = zp->conf; 134 135 /* build the path of the .signed zone file */ 136 snprintf (path, sizeof (path), "%s/../%s.signed", conf->dir, conf->zonefile); 137 if ( conf != zp->conf ) /* if we read in a local config file.. */ 138 free (conf); /* ..free the memory used */ 139 140#else 141 /* currently we use the signed zone file name of the 142 * current directory for checking if the file exist. 143 * TODO: Instead we have to use the name of the zone file 144 * used in the parent dir (see above) 145 */ 146 147 ext = strrchr (zp->sfile, '.'); 148 if ( ext && strcmp (zp->sfile, ".dsigned") == 0 ) /* is the current zone a dynamic one ? */ 149 /* hack: we are using the standard zone file name for a static zone here */ 150 snprintf (path, sizeof (path), "%s/../%s", zp->dir, "zone.db.signed"); 151 else 152 { 153# if 1 154 const zone_t *parent; 155 const char *parentname; 156 157 /* find out name of parent */ 158 parentname = strchr (zp->zone, '.'); /* find first dot in zone name */ 159 if ( parentname == NULL ) /* no parent found! */ 160 return 0; 161 parentname += 1; /* skip '.' */ 162 163 /* try to find parent zone in zonelist */ 164 if ( (parent = zone_search (zonelist, parentname)) == NULL ) 165 return 0; 166 snprintf (path, sizeof (path), "%s/%s", parent->dir, parent->sfile); 167# else 168 snprintf (path, sizeof (path), "%s/../%s", zp->dir, zp->sfile); 169# endif 170 } 171#endif 172lg_mesg (LG_DEBUG, "%s: is_parentdirsigned = %d fileexist (%s)\n", zp->zone, fileexist (path), path); 173 return fileexist (path); /* parent dir has zone.db.signed file ? */ 174} 175 176/***************************************************************** 177** create_parent_file () 178*****************************************************************/ 179static int create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp) 180{ 181 FILE *fp; 182 183 assert ( fname != NULL ); 184 185 if ( dkp == NULL || (phase != 1 && phase != 2) ) 186 return 0; 187 188 if ( (fp = fopen (fname, "w")) == NULL ) 189 fatal ("can\'t create new parentfile \"%s\"\n", fname); 190 191 if ( phase == 1 ) 192 fprintf (fp, "; KSK rollover phase1 (new key generated but this is alread the old one)\n"); 193 else 194 fprintf (fp, "; KSK rollover phase2 (this is the new key)\n"); 195 196 dki_prt_dnskeyttl (dkp, fp, ttl); 197 fclose (fp); 198 199 return phase; 200} 201 202/***************************************************************** 203** get_parent_phase () 204*****************************************************************/ 205static int get_parent_phase (const char *file) 206{ 207 FILE *fp; 208 int phase; 209 210 if ( (fp = fopen (file, "r")) == NULL ) 211 return -1; 212 213 phase = 0; 214 if ( fscanf (fp, "; KSK rollover phase%d", &phase) != 1 ) 215 phase = 0; 216 217 fclose (fp); 218 return phase; 219} 220 221/***************************************************************** 222** kskrollover () 223*****************************************************************/ 224static int kskrollover (dki_t *ksk, zone_t *zonelist, zone_t *zp) 225{ 226 char path[MAX_PATHSIZE+1]; 227 const zconf_t *z; 228 time_t lifetime; 229 time_t currtime; 230 time_t age; 231 int currphase; 232 int parfile_age; 233 int parent_propagation; 234 int parent_resign; 235 int parent_keyttl; 236 237 238 assert ( ksk != NULL ); 239 assert ( zp != NULL ); 240 241 z = zp->conf; 242 /* check ksk lifetime */ 243 if ( (lifetime = dki_lifetime (ksk)) == 0 ) /* if lifetime of key is not set.. */ 244 lifetime = z->k_life; /* ..use global configured lifetime */ 245 246 currtime = time (NULL); 247 age = dki_age (ksk, currtime); 248 249 /* build path of parent-file */ 250 pathname (path, sizeof (path), zp->dir, "parent-", zp->zone); 251 252 /* check if we have to change the ksk ? */ 253 if ( lifetime > 0 && age > lifetime && !fileexist (path) ) /* lifetime is over and no kskrollover in progress */ 254 { 255 /* we are in hierachical mode and the parent directory contains a signed zone ? */ 256 if ( z->keysetdir && strcmp (z->keysetdir, "..") == 0 && is_parentdirsigned (zonelist, zp) ) 257 { 258 verbmesg (2, z, "\t\tkskrollover: create new key signing key\n"); 259 /* create a new key: this is phase one of a double signing key rollover */ 260 ksk = genkey (&zp->keys, zp->dir, zp->zone, DKI_KSK, z, DKI_ACTIVE); 261 if ( ksk == NULL ) 262 { 263 lg_mesg (LG_ERROR, "\"%s\": unable to generate new ksk for double signing rollover", zp->zone); 264 return 0; 265 } 266 lg_mesg (LG_INFO, "\"%s\": kskrollover phase1: New key %d generated", zp->zone, ksk->tag); 267 268 /* find the oldest active ksk to create the parent file */ 269 if ( (ksk = (dki_t *)dki_findalgo (zp->keys, DKI_KSK, zp->conf->k_algo, 'a', 1)) == NULL ) 270 lg_mesg (LG_ERROR, "kskrollover phase1: Couldn't find the old active key\n"); 271 if ( !create_parent_file (path, 1, z->key_ttl, ksk) ) 272 lg_mesg (LG_ERROR, "Couldn't create parentfile %s\n", path); 273 274 } 275 else /* print out a warning only */ 276 { 277 logmesg ("\t\tWarning: Lifetime of Key Signing Key %d exceeded: %s\n", 278 ksk->tag, str_delspace (age2str (age))); 279 lg_mesg (LG_WARNING, "\"%s\": lifetime of key signing key %d exceeded since %s", 280 zp->zone, ksk->tag, str_delspace (age2str (age - lifetime))); 281 } 282 return 1; 283 } 284 285 /* now check if there is an ongoing key rollover */ 286 287 /* check if parent-file already exist */ 288 if ( !fileexist (path) ) /* no parent-<zone> file found ? */ 289 return 0; /* ok, that's it */ 290 291 /* check the ksk rollover phase we are in */ 292 currphase = get_parent_phase (path); /* this is the actual state we are in */ 293 parfile_age = file_age (path); 294 295 /* TODO: Set these values to the one found in the parent dnssec.conf file */ 296 parent_propagation = PARENT_PROPAGATION; 297 parent_resign = z->resign; 298 parent_keyttl = z->key_ttl; 299 300 switch ( currphase ) 301 { 302 case 1: /* we are currently in state one (new ksk already generated) */ 303 if ( parfile_age > z->proptime + z->key_ttl ) /* can we go to phase 2 ? */ 304 { 305 verbmesg (2, z, "\t\tkskrollover: save new ksk in parent file\n"); 306 ksk = ksk->next; /* set ksk to new ksk */ 307 if ( !create_parent_file (path, currphase+1, z->key_ttl, ksk) ) 308 lg_mesg (LG_ERROR, "Couldn't create parentfile %s\n", path); 309 lg_mesg (LG_INFO, "\"%s\": kskrollover phase2: send new key %d to the parent zone", zp->zone, ksk->tag); 310 return 1; 311 } 312 else 313 verbmesg (2, z, "\t\tkskrollover: we are in state 1 and waiting for propagation of the new key (parentfile %dsec < prop %dsec + keyttl %dsec\n", parfile_age, z->proptime, z->key_ttl); 314 break; 315 case 2: /* we are currently in state two (propagation of new key to the parent) */ 316#if 0 317 if ( parfile_age >= parent_propagation + parent_resign + parent_keyttl ) /* can we go to phase 3 ? */ 318#else 319 if ( parfile_age >= parent_propagation + parent_keyttl ) /* can we go to phase 3 ? */ 320#endif 321 { 322 /* remove the parentfile */ 323 unlink (path); 324 325 /* remove oldest key from list and mark file as removed */ 326 zp->keys = dki_remove (ksk); 327 328 // verbmesg (2, z, "kskrollover: remove parentfile and rename old key to k<zone>+<algo>+<tag>.key\n"); 329 verbmesg (2, z, "\t\tkskrollover: remove parentfile and rename old key to k%s+%03d+%05d.key\n", 330 ksk->name, ksk->algo, ksk->tag); 331 lg_mesg (LG_INFO, "\"%s\": kskrollover phase3: Remove old key %d", zp->zone, ksk->tag); 332 return 1; 333 } 334 else 335#if 0 336 verbmesg (2, z, "\t\tkskrollover: we are in state 2 and waiting for parent propagation (parentfile %d < parentprop %d + parentresig %d + parentkeyttl %d\n", parfile_age, parent_propagation, parent_resign, parent_keyttl); 337#else 338 verbmesg (2, z, "\t\tkskrollover: we are in state 2 and waiting for parent propagation (parentfile %dsec < parentprop %dsec + parentkeyttl %dsec\n", parfile_age, parent_propagation, parent_keyttl); 339#endif 340 break; 341 default: 342 assert ( currphase == 1 || currphase == 2 ); 343 /* NOTREACHED */ 344 } 345 346 return 0; 347} 348 349/***************************************************************** 350** global function definition 351*****************************************************************/ 352 353/***************************************************************** 354** ksk5011status () 355** Check if the list of zone keys containing a revoked or a 356** standby key. 357** Remove the revoked key if it is older than 30 days. 358** If the lifetime of the active key is reached, do a rfc5011 359** keyrollover. 360** Returns an int with the rightmost bit set if a resigning 361** is required. The second rightmost bit is set, if it is an 362** rfc5011 zone. 363*****************************************************************/ 364int ksk5011status (dki_t **listp, const char *dir, const char *domain, const zconf_t *z) 365{ 366 dki_t *standbykey; 367 dki_t *activekey; 368 dki_t *dkp; 369 dki_t *prev; 370 time_t currtime; 371 time_t exptime; 372 int ret; 373 374 assert ( listp != NULL ); 375 assert ( z != NULL ); 376 377 if ( z->k_life == 0 ) 378 return 0; 379 380 verbmesg (1, z, "\tCheck RFC5011 status\n"); 381 382 ret = 0; 383 currtime = time (NULL); 384 385 /* go through the list of key signing keys, */ 386 /* remove revoked keys and set a pointer to standby and active key */ 387 standbykey = activekey = NULL; 388 prev = NULL; 389 for ( dkp = *listp; dkp && dki_isksk (dkp); dkp = dkp->next ) 390 { 391 exptime = get_exptime (dkp, z); 392 if ( dki_isrevoked (dkp) ) 393 lg_mesg (LG_DEBUG, "zone \"%s\": found revoked key (id=%d exptime=%s); waiting for remove hold down time", 394 domain, dkp->tag, time2str (exptime, 's')); 395 396 /* revoked key is older than 30 days? */ 397 if ( dki_isrevoked (dkp) && currtime > exptime + REMOVE_HOLD_DOWN ) 398 { 399 verbmesg (1, z, "\tRemove revoked key %d which is older than 30 days\n", dkp->tag); 400 lg_mesg (LG_NOTICE, "zone \"%s\": removing revoked key %d", domain, dkp->tag); 401 402 /* remove key from list and mark file as removed */ 403 if ( prev == NULL ) /* at the beginning of the list ? */ 404 *listp = dki_remove (dkp); 405 else /* anywhere in the middle of the list */ 406 prev->next = dki_remove (dkp); 407 408 ret |= 01; /* from now on a resigning is necessary */ 409 } 410 411 /* remember oldest standby and active key */ 412 if ( dki_status (dkp) == DKI_PUBLISHED ) 413 standbykey = dkp; 414 if ( dki_status (dkp) == DKI_ACTIVE ) 415 activekey = dkp; 416 } 417 /* no activekey or no standby key and also no revoked key found ? */ 418 if ( activekey == NULL || (standbykey == NULL && ret == 0) ) 419 return ret; /* Seems that this is a non rfc5011 zone! */ 420 421 ret |= 02; /* Zone looks like a rfc5011 zone */ 422 423 exptime = get_exptime (activekey, z); 424#if 0 425 lg_mesg (LG_DEBUG, "Act Exptime: %s", time2str (exptime, 's')); 426 lg_mesg (LG_DEBUG, "Stb time: %s", time2str (dki_time (standbykey), 's')); 427 lg_mesg (LG_DEBUG, "Stb time+wait: %s", time2str (dki_time (standbykey) + min (DAYSEC * 30, z->key_ttl), 's')); 428#endif 429 /* At the first time we introduce a standby key, the lifetime of the current KSK shouldn't be expired, */ 430 /* otherwise we run into an (nearly) immediate key rollover! */ 431 if ( currtime > exptime && currtime > dki_time (standbykey) + min (ADD_HOLD_DOWN, z->key_ttl) ) 432 { 433 lg_mesg (LG_NOTICE, "\"%s\": starting rfc5011 rollover", domain); 434 verbmesg (1, z, "\tLifetime of Key Signing Key %d exceeded (%s): Starting rfc5011 rollover!\n", 435 activekey->tag, str_delspace (age2str (dki_age (activekey, currtime)))); 436 verbmesg (2, z, "\t\t=>Generating new standby key signing key\n"); 437 dkp = genkey (listp, dir, domain, DKI_KSK, z, DKI_PUBLISHED); /* gentime == now; lifetime = z->k_life; exp = 0 */ 438 if ( !dkp ) 439 { 440 error ("\tcould not generate new standby KSK\n"); 441 lg_mesg (LG_ERROR, "\%s\": can't generate new standby KSK", domain); 442 } 443 else 444 lg_mesg (LG_NOTICE, "\"%s\": generated new standby KSK %d", domain, dkp->tag); 445 446 /* standby key gets active */ 447 verbmesg (2, z, "\t\t=>Activating old standby key %d \n", standbykey->tag); 448 dki_setstatus (standbykey, DKI_ACT); 449 450 /* active key should be revoked */ 451 verbmesg (2, z, "\t\t=>Revoking old active key %d \n", activekey->tag); 452 dki_setstatus (activekey, DKI_REVOKED); 453 dki_setexptime (activekey, currtime); /* now the key is expired */ 454 455 ret |= 01; /* resigning necessary */ 456 } 457 458 return ret; 459} 460 461/***************************************************************** 462** kskstatus () 463** Check the ksk status of a zone if a ksk lifetime is set. 464** If there is no key signing key present create a new one. 465** Prints out a warning message if the lifetime of the current 466** key signing key is over. 467** Returns 1 if a resigning of the zone is necessary, otherwise 468** the function returns 0. 469*****************************************************************/ 470int kskstatus (zone_t *zonelist, zone_t *zp) 471{ 472 dki_t *akey; 473 const zconf_t *z; 474 475 assert ( zp != NULL ); 476 477 z = zp->conf; 478 if ( z->k_life == 0 ) 479 return 0; 480 481 verbmesg (1, z, "\tCheck KSK status\n"); 482 /* check if a key signing key exist ? */ 483 akey = (dki_t *)dki_findalgo (zp->keys, DKI_KSK, z->k_algo, 'a', 1); 484 if ( akey == NULL ) 485 { 486 verbmesg (1, z, "\tNo active KSK found: generate new one\n"); 487 akey = genkey (&zp->keys, zp->dir, zp->zone, DKI_KSK, z, DKI_ACTIVE); 488 if ( !akey ) 489 { 490 error ("\tcould not generate new KSK\n"); 491 lg_mesg (LG_ERROR, "\"%s\": can't generate new KSK: \"%s\"", 492 zp->zone, dki_geterrstr()); 493 } 494 else 495 lg_mesg (LG_INFO, "\"%s\": generated new KSK %d", zp->zone, akey->tag); 496 return akey != NULL; /* return value of 1 forces a resigning of the zone */ 497 } 498 else /* try to start a full automated ksk rollover */ 499 kskrollover (akey, zonelist, zp); 500 501 /* is a second algorithm requested ? (since 0.99) */ 502 if ( z->k2_algo && z->k2_algo != z->k_algo ) 503 { 504 /* check for ksk supporting the additional algorithm */ 505 akey = (dki_t *)dki_findalgo (zp->keys, DKI_KSK, z->k2_algo, 'a', 1); 506 if ( akey == NULL ) 507 { 508 verbmesg (1, z, "\tNo active KSK for additional algorithm found: generate new one\n"); 509 akey = genkey2 (&zp->keys, zp->dir, zp->zone, DKI_KSK, z, DKI_ACTIVE); 510 if ( !akey ) 511 { 512 error ("\tcould not generate new KSK for additional algorithm\n"); 513 lg_mesg (LG_ERROR, "\"%s\": can't generate new KSK for 2nd algorithm: \"%s\"", 514 zp->zone, dki_geterrstr()); 515 } 516 else 517 lg_mesg (LG_INFO, "\"%s\": generated new KSK %d for additional algorithm", 518 zp->zone, akey->tag); 519 return 1; /* return value of 1 forces a resigning of the zone */ 520 } 521 } 522 523 return 0; 524} 525 526/***************************************************************** 527** zskstatus () 528** Check the zsk status of a zone. 529** Returns 1 if a resigning of the zone is necessary, otherwise 530** the function returns 0. 531*****************************************************************/ 532int zskstatus (dki_t **listp, const char *dir, const char *domain, const zconf_t *z) 533{ 534 dki_t *akey; 535 dki_t *nextkey; 536 dki_t *dkp, *last; 537 int keychange; 538 time_t lifetime; 539 time_t age; 540 time_t currtime; 541 542 assert ( listp != NULL ); 543 /* dir can be NULL */ 544 assert ( domain != NULL ); 545 assert ( z != NULL ); 546 547 currtime = time (NULL); 548 549 verbmesg (1, z, "\tCheck ZSK status\n"); 550 dbg_val("zskstatus for %s \n", domain); 551 keychange = 0; 552 /* Is the depreciated key expired ? */ 553 /* As mentioned by olaf, this is the max_ttl of all the rr in the zone */ 554 lifetime = z->max_ttl + z->proptime; /* draft kolkman/gieben */ 555 last = NULL; 556 dkp = *listp; 557 while ( dkp ) 558 if ( !dki_isksk (dkp) && 559 dki_status (dkp) == DKI_DEPRECIATED && 560 dki_age (dkp, currtime) > lifetime ) 561 { 562 keychange = 1; 563 verbmesg (1, z, "\tLifetime(%d sec) of depreciated key %d exceeded (%d sec)\n", 564 lifetime, dkp->tag, dki_age (dkp, currtime)); 565 lg_mesg (LG_INFO, "\"%s\": old ZSK %d removed", domain, dkp->tag); 566 dkp = dki_destroy (dkp); /* delete the keyfiles */ 567 dbg_msg("zskstatus: depreciated key removed "); 568 if ( last ) 569 last->next = dkp; 570 else 571 *listp = dkp; 572 verbmesg (1, z, "\t\t->remove it\n"); 573 } 574 else 575 { 576 last = dkp; 577 dkp = dkp->next; 578 } 579 580 /* check status of active key */ 581 dbg_msg("zskstatus check status of active key "); 582 lifetime = z->z_life; /* global configured lifetime for zsk */ 583 akey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k_algo, 'a', 1); 584 if ( akey == NULL && lifetime > 0 ) /* no active key found */ 585 { 586 verbmesg (1, z, "\tNo active ZSK found: generate new one\n"); 587 akey = genkey (listp, dir, domain, DKI_ZSK, z, DKI_ACTIVE); 588 lg_mesg (LG_INFO, "\"%s\": generated new ZSK %d", domain, akey->tag); 589 } 590 else /* active key exist */ 591 { 592 if ( dki_lifetime (akey) ) 593 lifetime = dki_lifetime (akey); /* set lifetime to lt of active key */ 594 595 /* lifetime of active key is expired and published key exist ? */ 596 age = dki_age (akey, currtime); 597 if ( lifetime > 0 && age > lifetime - (OFFSET) ) 598 { 599 verbmesg (1, z, "\tLifetime(%d +/-%d sec) of active key %d exceeded (%d sec)\n", 600 lifetime, (OFFSET) , akey->tag, dki_age (akey, currtime) ); 601 602 /* depreciate the key only if there is another active or published key */ 603 if ( (nextkey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k_algo, 'a', 2)) == NULL || 604 nextkey == akey ) 605 nextkey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k_algo, 'p', 1); 606 607 /* Is the published key sufficient long in the zone ? */ 608 /* As mentioned by Olaf, this should be the ttl of the DNSKEY RR ! */ 609 if ( nextkey && dki_age (nextkey, currtime) > z->key_ttl + z->proptime ) 610 { 611 keychange = 1; 612 verbmesg (1, z, "\t\t->depreciate it\n"); 613 dki_setstatus (akey, 'd'); /* depreciate the active key */ 614 verbmesg (1, z, "\t\t->activate published key %d\n", nextkey->tag); 615 dki_setstatus (nextkey, 'a'); /* activate published key */ 616 lg_mesg (LG_NOTICE, "\"%s\": lifetime of zone signing key %d exceeded: ZSK rollover done", domain, akey->tag); 617 akey = nextkey; 618 nextkey = NULL; 619 lifetime = dki_lifetime (akey); /* set lifetime to lt of the new active key (F. Behrens) */ 620 } 621 else 622 { 623 verbmesg (1, z, "\t\t->waiting for published key\n"); 624 lg_mesg (LG_NOTICE, "\"%s\": lifetime of zone signing key %d exceeded since %s: ZSK rollover deferred: waiting for published key", 625 domain, akey->tag, str_delspace (age2str (age - lifetime))); 626 } 627 } 628 } 629 /* Should we add a new publish key? This is necessary if the active 630 * key will be expired at the next re-signing interval (The published 631 * time will be checked just before the active key will be removed. 632 * See above). 633 */ 634 nextkey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k_algo, 'p', 1); 635 if ( nextkey == NULL && lifetime > 0 && (akey == NULL || 636 dki_age (akey, currtime + z->resign) > lifetime - (OFFSET)) ) 637 { 638 keychange = 1; 639 verbmesg (1, z, "\tNew key for publishing needed\n"); 640 nextkey = genkey (listp, dir, domain, DKI_ZSK, z, DKI_PUB); 641 642 if ( nextkey ) 643 { 644 verbmesg (1, z, "\t\t->creating new key %d\n", nextkey->tag); 645 lg_mesg (LG_INFO, "\"%s\": new key %d generated for publishing", domain, nextkey->tag); 646 } 647 else 648 { 649 error ("\tcould not generate new ZSK: \"%s\"\n", dki_geterrstr()); 650 lg_mesg (LG_ERROR, "\"%s\": can't generate new ZSK: \"%s\"", 651 domain, dki_geterrstr()); 652 } 653 } 654 655 /* is a second algorithm requested ? (since 0.99) */ 656 if ( z->k2_algo && z->k2_algo != z->k_algo ) 657 { 658 /* check for zsk supporting the additional algorithm */ 659 akey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k2_algo, 'a', 1); 660 if ( akey == NULL ) 661 { 662 verbmesg (1, z, "\tNo active ZSK for second algorithm found: generate new one\n"); 663 akey = genkey2 (listp, dir, domain, DKI_ZSK, z, DKI_ACTIVE); 664 if ( !akey ) 665 { 666 error ("\tcould not generate new ZSK for 2nd algorithm\n"); 667 lg_mesg (LG_ERROR, "\"%s\": can't generate new ZSK for 2nd algorithm: \"%s\"", 668 domain, dki_geterrstr()); 669 } 670 else 671 lg_mesg (LG_INFO, "\"%s\": generated new ZSK %d for 2nd algorithm", 672 domain, akey->tag); 673 return 1; /* return value of 1 forces a resigning of the zone */ 674 } 675 } 676 677 return keychange; 678} 679 680