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