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 
65 static	dki_t	*genkey (int addkey, dki_t **listp, const char *dir, const char *domain, int ksk, const zconf_t *conf, int status);
66 
67 /*	generate the first (or primary) key (algorithm k_algo) */
genfirstkey(dki_t ** listp,const char * dir,const char * domain,int ksk,const zconf_t * conf,int status)68 static	dki_t	*genfirstkey (dki_t **listp, const char *dir, const char *domain, int ksk, const zconf_t *conf, int status)
69 {
70 	return genkey (0, listp, dir, domain, ksk, conf, status);
71 }
72 
73 /*	generate the additional (or second) key (algorithm k2_algo) */
genaddkey(dki_t ** listp,const char * dir,const char * domain,int ksk,const zconf_t * conf,int status)74 static	dki_t	*genaddkey (dki_t **listp, const char *dir, const char *domain, int ksk, const zconf_t *conf, int status)
75 {
76 	return genkey (1, listp, dir, domain, ksk, conf, status);
77 }
78 
79 
80 /*	generate a DNSKEY key  */
genkey(int addkey,dki_t ** listp,const char * dir,const char * domain,int ksk,const zconf_t * conf,int status)81 static	dki_t	*genkey (int addkey, dki_t **listp, const char *dir, const char *domain, int ksk, const zconf_t *conf, int status)
82 {
83 	dki_t	*dkp;
84 	int	confalgo;
85 	int	algo;
86 
87 #if 0
88 	if ( listp == NULL || domain == NULL )
89 		return NULL;
90 #else
91 	assert ( listp != NULL );
92 	assert ( domain != NULL );
93 #endif
94 
95 	if ( addkey )	/* generating an additional key ? */
96 		confalgo = conf->k2_algo;
97 	else
98 		confalgo = conf->k_algo;
99 
100 	algo = confalgo;
101 	if ( conf->nsec3 != NSEC3_OFF )		/* is nsec3 turned on ? */
102 	{
103 		if ( confalgo == DK_ALGO_RSASHA1 )
104 			algo = DK_ALGO_NSEC3RSASHA1;
105 		else if ( confalgo == DK_ALGO_DSA )
106 			algo = DK_ALGO_NSEC3DSA;
107 	}
108 
109 	if ( ksk )
110 		dkp = dki_new (dir, domain, DKI_KSK, algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC);
111 	else
112 		dkp = dki_new (dir, domain, DKI_ZSK, algo, conf->z_bits, conf->z_random, conf->z_life / DAYSEC);
113 	dki_add (listp, dkp);
114 	dki_setstatus (dkp, status);
115 
116 	return dkp;
117 }
118 
119 /* get expiration time */
get_exptime(dki_t * key,const zconf_t * z)120 static	time_t	get_exptime (dki_t *key, const zconf_t *z)
121 {
122 	time_t	exptime;
123 
124 	exptime = dki_exptime (key);
125 	if ( exptime == 0L )
126 	{
127 		if ( dki_lifetime (key) )
128 			exptime = dki_time (key) + dki_lifetime (key);
129 		else
130 			exptime = dki_time (key) + z->k_life;
131 	}
132 
133 	return exptime;
134 }
135 
136 /*****************************************************************
137 **	is_parentdirsigned (name)
138 **	Check if the parent directory of the zone specified by zp
139 **	is a directory with a signed zone
140 **	Returns 0 | 1
141 *****************************************************************/
is_parentdirsigned(const zone_t * zonelist,const zone_t * zp)142 static	int	is_parentdirsigned (const zone_t *zonelist, const zone_t *zp)
143 {
144 	char	path[MAX_PATHSIZE+1];
145 	const	char	*ext;
146 #if 0
147 	const	zconf_t	*conf;
148 
149 	/* check if there is a local config file to get the name of the zone file */
150 	snprintf (path, sizeof (path), "%s/../%s", zp->dir, LOCALCONF_FILE);
151 	if ( fileexist (path) )		/* parent dir has local config file ? */
152 		conf = loadconfig (path, NULL);
153 	else
154 		conf = zp->conf;
155 
156 	/* build the path of the .signed zone file */
157 	snprintf (path, sizeof (path), "%s/../%s.signed", conf->dir, conf->zonefile);
158 	if ( conf != zp->conf )	/* if we read in a local config file.. */
159 		free (conf);	/* ..free the memory used */
160 
161 #else
162 	/* currently we use the signed zone file name of the
163 	 * current directory for checking if the file exist.
164 	 * TODO: Instead we have to use the name of the zone file
165 	 * used in the parent dir (see above)
166 	 */
167 
168 	ext = strrchr (zp->sfile, '.');
169 	if ( ext && strcmp (zp->sfile, ".dsigned") == 0 )	/* is the current zone a dynamic one ? */
170 		/* hack: we are using the standard zone file name for a static zone here */
171 		snprintf (path, sizeof (path), "%s/../%s", zp->dir, "zone.db.signed");
172 	else
173 	{
174 # if 1
175 		const	zone_t	*parent;
176 		const	char	*parentname;
177 
178 		/* find out name of parent */
179 		parentname = strchr (zp->zone, '.');	/* find first dot in zone name */
180 		if ( parentname == NULL )	/* no parent found! */
181 			return 0;
182 		parentname += 1;	/* skip '.' */
183 
184 		/* try to find parent zone in zonelist */
185 		if ( (parent = zone_search (zonelist, parentname)) == NULL )
186 			return 0;
187 		snprintf (path, sizeof (path), "%s/%s", parent->dir, parent->sfile);
188 # else
189 		snprintf (path, sizeof (path), "%s/../%s", zp->dir, zp->sfile);
190 # endif
191 	}
192 #endif
193 lg_mesg (LG_DEBUG, "%s: is_parentdirsigned = %d fileexist (%s)\n", zp->zone, fileexist (path), path);
194 	return fileexist (path);	/* parent dir has zone.db.signed file ? */
195 }
196 
197 /*****************************************************************
198 **	create_parent_file ()
199 *****************************************************************/
create_parent_file(const char * fname,int phase,int ttl,const dki_t * dkp)200 static	int	create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp)
201 {
202 	FILE	*fp;
203 
204 	assert ( fname != NULL );
205 
206 	if ( dkp == NULL || (phase != 1 && phase != 2) )
207 		return 0;
208 
209 	if ( (fp = fopen (fname, "w")) == NULL )
210 		fatal ("can\'t create new parentfile \"%s\"\n", fname);
211 
212 	if ( phase == 1 )
213 		fprintf (fp, "; KSK rollover phase1 (new key generated but this is alread the old one)\n");
214 	else
215 		fprintf (fp, "; KSK rollover phase2 (this is the new key)\n");
216 
217 	dki_prt_dnskeyttl (dkp, fp, ttl);
218 	fclose (fp);
219 
220 	return phase;
221 }
222 
223 /*****************************************************************
224 **	get_parent_phase ()
225 *****************************************************************/
get_parent_phase(const char * file)226 static	int	get_parent_phase (const char *file)
227 {
228 	FILE	*fp;
229 	int	phase;
230 
231 	if ( (fp = fopen (file, "r")) == NULL )
232 		return -1;
233 
234 	phase = 0;
235 	 if ( fscanf (fp, "; KSK rollover phase%d", &phase) != 1 )
236 		phase = 0;
237 
238 	fclose (fp);
239 	return phase;
240 }
241 
242 #if defined (USE_DS_TRACKING) && USE_DS_TRACKING
243 /*****************************************************************
244 **	is_published_in_parent ()
245 **	Use "dig" to track if the DS of the given KSK is published
246 **	in the parent zone
247 *****************************************************************/
is_published_in_parent(const zone_t * zp,const dki_t * ksk)248 static int	is_published_in_parent(const zone_t *zp, const dki_t *ksk)
249 {
250 	char	cmd[2047+1];
251 	char	str[1023+1];
252 	int	exicode;
253 	long	tag;
254 	FILE	*fp;
255 
256 	assert ( ksk != NULL );
257 	assert ( zp != NULL );
258 
259 	//snprintf (cmd, sizeof (cmd), "/usr/bin/dig +short %s DS | /bin/grep \"^%d \"", zp->zone, ksk->tag);
260 	snprintf (cmd, sizeof (cmd), "%s +short -t DS %s 2>&1", DIG_PATH, zp->zone);
261 
262 	verbmesg (2, zp->conf, "\t  Run cmd \"%s\"\n", cmd);
263 
264 	str[0] = '\0';
265 	if ( (fp = popen (cmd, "r")) == NULL )
266 		return -1;
267 
268 	tag = -1;	/* never getting this, even if atol() couldn't parse an integer */
269 	while ( fgets (str, sizeof str, fp) != NULL )	/* search for the right tag */
270 	{
271 		tag = atol (str);
272 		if ( tag == ksk->tag )
273 			break;
274 	}
275 
276 	exitcode = pclose (fp);
277 
278 	dbg_line ();
279 
280 	str_chop (str, '\n');
281 	verbmesg (2, zp->conf, "\t  Cmd dig returns with exitcode=%d: \"%s\"; DS tag %ld found looking for %u\n",
282 									exitcode, str, tag, ksk->tag);
283 
284 	return ( tag == ksk->tag );
285 }
286 #endif
287 
288 /*****************************************************************
289 **	kskrollover ()
290 *****************************************************************/
kskrollover(dki_t * ksk,zone_t * zonelist,zone_t * zp)291 static	int	kskrollover (dki_t *ksk, zone_t *zonelist, zone_t *zp)
292 {
293 	char	path[MAX_PATHSIZE+1];
294 	const	zconf_t	*z;
295 	time_t	lifetime;
296 	time_t	currtime;
297 	time_t	age;
298 	int	currphase;
299 	int	parfile_age;
300 	int	parent_propagation;
301 #if defined(PARENT_RESIGN)	/* parent_resign no longer used */
302 	int	parent_resign;
303 #endif
304 	int	parent_keyttl;
305 
306 
307 	assert ( ksk != NULL );
308 	assert ( zp != NULL );
309 
310 	z = zp->conf;
311 	/* check ksk lifetime */
312 	if ( (lifetime = dki_lifetime (ksk)) == 0 )	/* if lifetime of key is not set.. */
313 		lifetime = z->k_life;			/* ..use global configured lifetime */
314 
315 	currtime = time (NULL);
316 	age = dki_age (ksk, currtime);
317 
318 	/* build path of parent-file */
319 	pathname (path, sizeof (path), zp->dir, "parent-", zp->zone);
320 
321 	/* check if we have to change the ksk ? */
322 	if ( lifetime > 0 && age > lifetime && !fileexist (path) )	/* lifetime is over and no kskrollover in progress */
323 	{
324 		/* we are in hierachical mode and the parent directory contains a signed zone ? */
325 		if ( z->keysetdir && strcmp (z->keysetdir, "..") == 0 && is_parentdirsigned (zonelist, zp) )
326 		{
327 			verbmesg (2, z, "\t\tkskrollover: create new key signing key\n");
328 			/* create a new key: this is phase one of a double signing key rollover */
329 			ksk = genfirstkey (&zp->keys, zp->dir, zp->zone, DKI_KSK, z, DKI_ACTIVE);
330 			if ( ksk == NULL )
331 			{
332 				lg_mesg (LG_ERROR, "\"%s\": unable to generate new ksk for double signing rollover", zp->zone);
333 				return 0;
334 			}
335 			lg_mesg (LG_INFO, "\"%s\": kskrollover phase1: New key %d generated", zp->zone, ksk->tag);
336 
337 			/* find the oldest active ksk to create the parent file */
338 			if ( (ksk = (dki_t *)dki_findalgo (zp->keys, DKI_KSK, zp->conf->k_algo, 'a', 1)) == NULL )
339 				lg_mesg (LG_ERROR, "kskrollover phase1: Couldn't find the old active key\n");
340 			if ( !create_parent_file (path, 1, z->key_ttl, ksk) )
341 				lg_mesg (LG_ERROR, "Couldn't create parentfile %s\n", path);
342 
343 		}
344 		else	/* print out a warning only */
345 		{
346 			logmesg ("\t\tWarning: Lifetime of Key Signing Key %d exceeded: %s\n",
347 							ksk->tag, str_delspace (age2str (age)));
348 			lg_mesg (LG_WARNING, "\"%s\": lifetime of key signing key %d exceeded since %s",
349 							zp->zone, ksk->tag, str_delspace (age2str (age - lifetime)));
350 		}
351 		return 1;
352 	}
353 
354 	/* now check if there is an ongoing key rollover */
355 
356 	/* check if parent-file already exist */
357 	if ( !fileexist (path) )	/* no parent-<zone> file found ? */
358 		return 0;	/* ok, that's it */
359 
360 	/* check the ksk rollover phase we are in */
361 	currphase = get_parent_phase (path);	/* this is the actual state we are in */
362 	parfile_age = file_age (path);
363 
364 	/* TODO: Set these values to the one found in the parent dnssec.conf file */
365 	parent_propagation = PARENT_PROPAGATION;
366 #if defined(PARENT_RESIGN)
367 	parent_resign = z->resign;
368 #endif
369 #if defined (USE_DS_TRACKING) && USE_DS_TRACKING
370 	parent_keyttl = 86400;		/* z->key_ttl; -> dnssec-keysign uses default TTL for */
371 					/* DS records, also registries such as denic use 1d */
372 #else
373 	parent_keyttl = z->key_ttl;
374 #endif
375 
376 	switch ( currphase )
377 	{
378 	case 1:	/* we are currently in state one (new ksk already generated) */
379 		if ( parfile_age > z->proptime + z->key_ttl )	/* can we go to phase 2 ? */
380 		{
381 			verbmesg (2, z, "\t\tkskrollover: save new ksk in parent file\n");
382 			ksk = ksk->next;    /* set ksk to new ksk */
383 			if ( !create_parent_file (path, currphase+1, z->key_ttl, ksk) )
384 				lg_mesg (LG_ERROR, "Couldn't create parentfile %s\n", path);
385 			lg_mesg (LG_INFO, "\"%s\": kskrollover phase2: send new key %d to the parent zone", zp->zone, ksk->tag);
386 #if defined (USE_DS_TRACKING) && USE_DS_TRACKING
387 			if ( !is_parentdirsigned (zonelist, zp) )
388 				verbmesg (0, z, "\"%s\": kskrollover phase2: repla key %d to the parent zone now\n", zp->zone, ksk->tag);
389 #endif
390 			return 1;
391 		}
392 		else
393 			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);
394 		break;
395 
396 	case 2:	/* we are currently in state two (propagation of new key to the parent) */
397 
398 #if defined (USE_DS_TRACKING) && USE_DS_TRACKING
399 		/* do not automatically go into phase3 if DS entry is not available in parent yet */
400 		if ( parfile_age >= parent_propagation + parent_keyttl && !is_published_in_parent (zp, ksk->next))
401 		{
402 			ksk = ksk->next;    /* set ksk to new ksk */
403 			if ( !is_parentdirsigned(zonelist, zp) )
404 			{
405 				lg_mesg (LG_INFO, "\"%s\": kskrollover phase2: new key %d not yet published in parent zone, already submitted?", zp->zone, ksk->tag);
406 				verbmesg (0, z, "\"%s\": kskrollover phase2: new key %d not yet published in parent zone, already submitted?\n", zp->zone, ksk->tag);
407 			}
408 			else
409 			{
410 				lg_mesg (LG_NOTICE, "\"%s\": kskrollover phase2: new key %d not yet published in parent zone, postponing phase3", zp->zone, ksk->tag);
411 				verbmesg (2, z, "\"%s\": kskrollover phase2: new key %d not yet published in parent zone, postponing phase3\n", zp->zone, ksk->tag);
412 			}
413 			return 0;
414 		}
415 #endif
416 
417 #if defined(PARENT_RESIGN)
418 		if ( parfile_age >= parent_propagation + parent_resign + parent_keyttl )	/* can we go to phase 3 ? */
419 #else
420 		if ( parfile_age >= parent_propagation + parent_keyttl )	/* can we go to phase 3 ? */
421 #endif
422 		{
423 			/* remove the parentfile */
424 			unlink (path);
425 
426 			/* remove oldest key from list and mark file as removed */
427 			zp->keys = dki_remove (ksk);
428 
429 			// verbmesg (2, z, "kskrollover: remove parentfile and rename old key to k<zone>+<algo>+<tag>.key\n");
430 			verbmesg (2, z, "\t\tkskrollover: remove parentfile and rename old key to k%s+%03d+%05d.key\n",
431 									ksk->name, ksk->algo, ksk->tag);
432 			lg_mesg (LG_INFO, "\"%s\": kskrollover phase3: Remove old key %d", zp->zone, ksk->tag);
433 			return 1;
434 		}
435 		else
436 #if defined(PARENT_RESIGN)
437 			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);
438 #else
439 			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);
440 #endif
441 		break;
442 	default:
443 		assert ( currphase == 1 || currphase == 2 );
444 		/* NOTREACHED */
445 	}
446 
447 	return 0;
448 }
449 
450 /*****************************************************************
451 **	global function definition
452 *****************************************************************/
453 
454 /*****************************************************************
455 **	ksk5011status ()
456 **	Check if the list of zone keys containing a revoked or a
457 **	standby key.
458 **	Remove the revoked key if it is older than 30 days.
459 **	If the lifetime of the active key is reached, do a rfc5011
460 **	keyrollover.
461 **	Returns an int with the rightmost bit set if a resigning
462 **	is required. The second rightmost bit is set, if it is an
463 **	rfc5011 zone.
464 *****************************************************************/
ksk5011status(dki_t ** listp,const char * dir,const char * domain,const zconf_t * z)465 int	ksk5011status (dki_t **listp, const char *dir, const char *domain, const zconf_t *z)
466 {
467 	dki_t	*standbykey;
468 	dki_t	*activekey;
469 	dki_t	*dkp;
470 	dki_t	*prev;
471 	time_t	currtime;
472 	time_t	exptime;
473 	int	ret;
474 
475 	assert ( listp != NULL );
476 	assert ( z != NULL );
477 
478 	if ( z->k_life == 0 )
479 		return 0;
480 
481 	verbmesg (1, z, "\tCheck RFC5011 status\n");
482 
483 	ret = 0;
484 	currtime = time (NULL);
485 
486 	/* go through the list of key signing keys,	*/
487 	/* remove revoked keys and set a pointer to standby and active key */
488 	standbykey = activekey = NULL;
489 	prev = NULL;
490 	for ( dkp = *listp; dkp && dki_isksk (dkp); dkp = dkp->next )
491 	{
492 		exptime = get_exptime (dkp, z);
493 		if ( dki_isrevoked (dkp) )
494 			lg_mesg (LG_DEBUG, "zone \"%s\": found revoked key (id=%d exptime=%s); waiting for remove hold down time",
495 							domain, dkp->tag, time2str (exptime, 's'));
496 
497 		/* revoked key is older than 30 days? */
498 		if ( dki_isrevoked (dkp) && currtime > exptime + REMOVE_HOLD_DOWN )
499 		{
500 			verbmesg (1, z, "\tRemove revoked key %d which is older than 30 days\n", dkp->tag);
501 			lg_mesg (LG_NOTICE, "zone \"%s\": removing revoked key %d", domain, dkp->tag);
502 
503 			/* remove key from list and mark file as removed */
504 			if ( prev == NULL )		/* at the beginning of the list ? */
505 				*listp = dki_remove (dkp);
506 			else				/* anywhere in the middle of the list */
507 				prev->next = dki_remove (dkp);
508 
509 			ret |= 01;		/* from now on a resigning is necessary */
510 		}
511 
512 		/* remember oldest standby and active key */
513 		if ( dki_status (dkp) == DKI_PUBLISHED )
514 			standbykey = dkp;
515 		if ( dki_status (dkp) == DKI_ACTIVE )
516 			activekey = dkp;
517 	}
518 				/* no activekey or no standby key and also no revoked key found ? */
519 	if ( activekey == NULL || (standbykey == NULL && ret == 0) )
520 		return ret;				/* Seems that this is a non rfc5011 zone! */
521 
522 	ret |= 02;		/* Zone looks like a rfc5011 zone */
523 
524 	exptime = get_exptime (activekey, z);
525 #if 0
526 	lg_mesg (LG_DEBUG, "Act Exptime: %s", time2str (exptime, 's'));
527 	lg_mesg (LG_DEBUG, "Stb time: %s", time2str (dki_time (standbykey), 's'));
528 	lg_mesg (LG_DEBUG, "Stb time+wait: %s", time2str (dki_time (standbykey) + min (DAYSEC * 30, z->key_ttl), 's'));
529 #endif
530 	/* At the first time we introduce a standby key, the lifetime of the current KSK shouldn't be expired, */
531 	/* otherwise we run into an (nearly) immediate key rollover!	*/
532 	if ( currtime > exptime && currtime > dki_time (standbykey) + min (ADD_HOLD_DOWN, z->key_ttl) )
533 	{
534 		lg_mesg (LG_NOTICE, "\"%s\": starting rfc5011 rollover", domain);
535 		verbmesg (1, z, "\tLifetime of Key Signing Key %d exceeded (%s): Starting rfc5011 rollover!\n",
536 							activekey->tag, str_delspace (age2str (dki_age (activekey, currtime))));
537 		verbmesg (2, z, "\t\t=>Generating new standby key signing key\n");
538 		dkp = genfirstkey (listp, dir, domain, DKI_KSK, z, DKI_PUBLISHED);	/* gentime == now; lifetime = z->k_life; exp = 0 */
539 		if ( !dkp )
540 		{
541 			error ("\tcould not generate new standby KSK\n");
542 			lg_mesg (LG_ERROR, "\%s\": can't generate new standby KSK", domain);
543 		}
544 		else
545 			lg_mesg (LG_NOTICE, "\"%s\": generated new standby KSK %d", domain, dkp->tag);
546 
547 		/* standby key gets active  */
548 		verbmesg (2, z, "\t\t=>Activating old standby key %d \n", standbykey->tag);
549 		dki_setstatus (standbykey, DKI_ACT);
550 
551 		/* active key should be revoked */
552 		verbmesg (2, z, "\t\t=>Revoking old active key %d \n", activekey->tag);
553 		dki_setstatus (activekey, DKI_REVOKED);
554 		dki_setexptime (activekey, currtime);	/* now the key is expired */
555 
556 		ret |= 01;		/* resigning necessary */
557 	}
558 
559 	return ret;
560 }
561 
562 /*****************************************************************
563 **	kskstatus ()
564 **	Check the ksk status of a zone if a ksk lifetime is set.
565 **	If there is no key signing key present create a new one.
566 **	Prints out a warning message if the lifetime of the current
567 **	key signing key is over.
568 **	Returns 1 if a resigning of the zone is necessary, otherwise
569 **	the function returns 0.
570 *****************************************************************/
kskstatus(zone_t * zonelist,zone_t * zp)571 int	kskstatus (zone_t *zonelist, zone_t *zp)
572 {
573 	dki_t	*akey;
574 	const	zconf_t	*z;
575 
576 	assert ( zp != NULL );
577 
578 	z = zp->conf;
579 	if ( z->k_life == 0 )
580 		return 0;
581 
582 	verbmesg (1, z, "\tCheck KSK status\n");
583 	/* check if a key signing key exist ? */
584 	akey = (dki_t *)dki_findalgo (zp->keys, DKI_KSK, z->k_algo, 'a', 1);
585 	if ( akey == NULL )
586 	{
587 		verbmesg (1, z, "\tNo active KSK found: generate new one\n");
588 		akey = genfirstkey (&zp->keys, zp->dir, zp->zone, DKI_KSK, z, DKI_ACTIVE);
589 		if ( !akey )
590 		{
591 			error ("\tcould not generate new KSK\n");
592 			lg_mesg (LG_ERROR, "\"%s\": can't generate new KSK: \"%s\"",
593 								zp->zone, dki_geterrstr());
594 		}
595 		else
596 			lg_mesg (LG_INFO, "\"%s\": generated new KSK %d", zp->zone, akey->tag);
597 		return akey != NULL;	/* return value of 1 forces a resigning of the zone */
598 	}
599 	else	/* try to start a full automated ksk rollover */
600 		kskrollover (akey, zonelist, zp);
601 
602 	/* is a second algorithm requested ? (since 0.99) */
603 	if ( z->k2_algo && z->k2_algo != z->k_algo )
604 	{
605 		/* check for ksk supporting the additional algorithm */
606 		akey = (dki_t *)dki_findalgo (zp->keys, DKI_KSK, z->k2_algo, 'a', 1);
607 		if ( akey == NULL )
608 		{
609 			verbmesg (1, z, "\tNo active KSK for additional algorithm found: generate new one\n");
610 			akey = genaddkey (&zp->keys, zp->dir, zp->zone, DKI_KSK, z, DKI_ACTIVE);
611 			if ( !akey )
612 			{
613 				error ("\tcould not generate new KSK for additional algorithm\n");
614 				lg_mesg (LG_ERROR, "\"%s\": can't generate new KSK for 2nd algorithm: \"%s\"",
615 									zp->zone, dki_geterrstr());
616 			}
617 			else
618 				lg_mesg (LG_INFO, "\"%s\": generated new KSK %d for additional algorithm",
619 										zp->zone, akey->tag);
620 			return 1;	/* return value of 1 forces a resigning of the zone */
621 		}
622 	}
623 
624 	return 0;
625 }
626 
627 /*****************************************************************
628 **	zskstatus ()
629 **	Check the zsk status of a zone.
630 **	Returns 1 if a resigning of the zone is necessary, otherwise
631 **	the function returns 0.
632 *****************************************************************/
zskstatus(dki_t ** listp,const char * dir,const char * domain,const zconf_t * z)633 int	zskstatus (dki_t **listp, const char *dir, const char *domain, const zconf_t *z)
634 {
635 	dki_t	*akey;
636 	dki_t	*nextkey;
637 	dki_t	*dkp, *last;
638 	int	keychange;
639 	time_t	lifetime;
640 	time_t	age;
641 	time_t	currtime;
642 
643 	assert ( listp != NULL );
644 	/* dir can be NULL */
645 	assert ( domain != NULL );
646 	assert ( z != NULL );
647 
648 	currtime = time (NULL);
649 
650 	verbmesg (1, z, "\tCheck ZSK status\n");
651 	dbg_val("zskstatus for %s \n", domain);
652 	keychange = 0;
653 	/* Is the depreciated key expired ? */
654 	/* As mentioned by olaf, this is the max_ttl of all the rr in the zone */
655 	lifetime = z->max_ttl + z->proptime;	/* draft kolkman/gieben */
656 	last = NULL;
657 	dkp = *listp;
658 	while ( dkp )
659 		if ( !dki_isksk (dkp) &&
660 		     dki_status (dkp) == DKI_DEPRECIATED &&
661 		     dki_age (dkp, currtime) > lifetime )
662 		{
663 			keychange = 1;
664 			verbmesg (1, z, "\tLifetime(%d sec) of depreciated key %d exceeded (%d sec)\n",
665 					 lifetime, dkp->tag, dki_age (dkp, currtime));
666 			lg_mesg (LG_INFO, "\"%s\": old ZSK %d removed", domain, dkp->tag);
667 			dkp = dki_destroy (dkp);	/* delete the keyfiles */
668 			dbg_msg("zskstatus: depreciated key removed ");
669 			if ( last )
670 				last->next = dkp;
671 			else
672 				*listp = dkp;
673 			verbmesg (1, z, "\t\t->remove it\n");
674 		}
675 		else
676 		{
677 			last = dkp;
678 			dkp = dkp->next;
679 		}
680 
681 	/* check status of active key */
682 	dbg_msg("zskstatus check status of active key ");
683 	lifetime = z->z_life;			/* global configured lifetime for zsk */
684 	akey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k_algo, 'a', 1);
685 	if ( akey == NULL && lifetime > 0 )	/* no active key found */
686 	{
687 		verbmesg (1, z, "\tNo active ZSK found: generate new one\n");
688 		akey = genfirstkey (listp, dir, domain, DKI_ZSK, z, DKI_ACTIVE);
689 		if ( !akey )
690 		{
691 			error ("\tcould not generate new ZSK\n");
692 			lg_mesg (LG_ERROR, "\%s\": can't generate new ZSK", domain);
693 		}
694 		else
695 			lg_mesg (LG_INFO, "\"%s\": generated new ZSK %d", domain, akey->tag);
696 	}
697 	else	/* active key exist */
698 	{
699 		if ( dki_lifetime (akey) )
700 			lifetime = dki_lifetime (akey);	/* set lifetime to lt of active key */
701 
702 		/* lifetime of active key is expired and published key exist ? */
703 		age = dki_age (akey, currtime);
704 		if ( lifetime > 0 && age > lifetime - (OFFSET) )
705 		{
706 			verbmesg (1, z, "\tLifetime(%d +/-%d sec) of active key %d exceeded (%d sec)\n",
707 					lifetime, (OFFSET) , akey->tag, dki_age (akey, currtime) );
708 
709 			/* depreciate the key only if there is another active or published key */
710 			if ( (nextkey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k_algo, 'a', 2)) == NULL ||
711 			      nextkey == akey )
712 				nextkey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k_algo, 'p', 1);
713 
714 			/* Is the published key sufficient long in the zone ? */
715 			/* As mentioned by Olaf, this should be the ttl of the DNSKEY RR ! */
716 			if ( nextkey && dki_age (nextkey, currtime) > z->key_ttl + z->proptime )
717 			{
718 				keychange = 1;
719 				verbmesg (1, z, "\t\t->depreciate it\n");
720 				dki_setstatus (akey, 'd');	/* depreciate the active key */
721 				verbmesg (1, z, "\t\t->activate published key %d\n", nextkey->tag);
722 				dki_setstatus (nextkey, 'a');	/* activate published key */
723 				lg_mesg (LG_NOTICE, "\"%s\": lifetime of zone signing key %d exceeded: ZSK rollover done", domain, akey->tag);
724 				akey = nextkey;
725 				nextkey = NULL;
726 				lifetime = dki_lifetime (akey);	/* set lifetime to lt of the new active key (F. Behrens) */
727 			}
728 			else
729 			{
730 				verbmesg (1, z, "\t\t->waiting for published key\n");
731 				lg_mesg (LG_NOTICE, "\"%s\": lifetime of zone signing key %d exceeded since %s: ZSK rollover deferred: waiting for published key",
732 						domain, akey->tag, str_delspace (age2str (age - lifetime)));
733 			}
734 		}
735 	}
736 
737 	/* Should we add a new publish key? */
738 	nextkey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k_algo, 'p', 1);	/* is there a published ZSK? */
739 #if defined(ALLOW_ALWAYS_PREPUBLISH_ZSK) && ALLOW_ALWAYS_PREPUBLISH_ZSK
740 	if ( z->z_always )	/* always add a pre-publish ZSK  (patch from Hrant Dadivanyan) */
741 	{
742 		if ( nextkey == NULL )
743 		{
744 			verbmesg (1, z, "\tNew key for pre-publishing needed\n");
745 			nextkey = genfirstkey (listp, dir, domain, DKI_ZSK, z, DKI_PUB);
746 			if ( nextkey )
747 			{
748 				keychange = 1;
749 				verbmesg (1, z, "\t\t->creating new key %d\n", nextkey->tag);
750 				lg_mesg (LG_INFO, "\"%s\": new key %d generated for pre-publishing", domain, nextkey->tag);
751 			}
752 			else
753 			{
754 				error ("\tcould not generate new ZSK: \"%s\"\n", dki_geterrstr());
755 				lg_mesg (LG_ERROR, "\"%s\": can't generate new ZSK: \"%s\"",
756 									domain, dki_geterrstr());
757 			}
758 		}
759 	}
760 	else	/* do we need a new ZSK ? */
761 #endif
762 	{
763 		/* This is necessary if the active key will be expired at the
764 		 * next re-signing interval (The published time will be checked
765 		 * just before the active key will be removed. See above).
766 		 */
767 		if ( nextkey == NULL && lifetime > 0 && (akey == NULL ||
768 		     dki_age (akey, currtime + z->resign) > lifetime - (OFFSET)) )
769 		{
770 			verbmesg (1, z, "\tNew ZSK for publishing needed\n");
771 			nextkey = genfirstkey (listp, dir, domain, DKI_ZSK, z, DKI_PUB);
772 			if ( nextkey )
773 			{
774 				keychange = 1;
775 				verbmesg (1, z, "\t\t->creating new key %d\n", nextkey->tag);
776 				lg_mesg (LG_INFO, "\"%s\": new zone signing key %d generated for publishing", domain, nextkey->tag);
777 			}
778 			else
779 			{
780 				error ("\tcould not generate new ZSK: \"%s\"\n", dki_geterrstr());
781 				lg_mesg (LG_ERROR, "\"%s\": can't generate new ZSK: \"%s\"",
782 									domain, dki_geterrstr());
783 			}
784 		}
785 	}
786 
787 	/* is a second algorithm requested ? (since 0.99) */
788 	if ( z->k2_algo && z->k2_algo != z->k_algo )
789 	{
790 		/* check for zsk supporting the additional algorithm */
791 		akey = (dki_t *)dki_findalgo (*listp, DKI_ZSK, z->k2_algo, 'a', 1);
792 		if ( akey == NULL )
793 		{
794 			verbmesg (1, z, "\tNo active ZSK for second algorithm found: generate new one\n");
795 			akey = genaddkey (listp, dir, domain, DKI_ZSK, z, DKI_ACTIVE);
796 			if ( !akey )
797 			{
798 				error ("\tcould not generate new ZSK for 2nd algorithm\n");
799 				lg_mesg (LG_ERROR, "\"%s\": can't generate new ZSK for 2nd algorithm: \"%s\"",
800 									domain, dki_geterrstr());
801 			}
802 			else
803 				lg_mesg (LG_INFO, "\"%s\": generated new ZSK %d for 2nd algorithm",
804 										domain, akey->tag);
805 			return 1;	/* return value of 1 forces a resigning of the zone */
806 		}
807 	}
808 
809 	return keychange;
810 }
811 
812