1 /*	$NetBSD: dki.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $	*/
2 
3 /*****************************************************************
4 **
5 **	@(#) dki.c  (c) Jan 2005  Holger Zuleger  hznet.de
6 **
7 **	A library for managing BIND dnssec key files.
8 **
9 **	Copyright (c) Jan 2005, Holger Zuleger HZnet. All rights reserved.
10 **
11 **	This software is open source.
12 **
13 **	Redistribution and use in source and binary forms, with or without
14 **	modification, are permitted provided that the following conditions
15 **	are met:
16 **
17 **	Redistributions of source code must retain the above copyright notice,
18 **	this list of conditions and the following disclaimer.
19 **
20 **	Redistributions in binary form must reproduce the above copyright notice,
21 **	this list of conditions and the following disclaimer in the documentation
22 **	and/or other materials provided with the distribution.
23 **
24 **	Neither the name of Holger Zuleger HZnet nor the names of its contributors may
25 **	be used to endorse or promote products derived from this software without
26 **	specific prior written permission.
27 **
28 **	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 **	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 **	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 **	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
32 **	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 **	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 **	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 **	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 **	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 **	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 **	POSSIBILITY OF SUCH DAMAGE.
39 **
40 **
41 *****************************************************************/
42 
43 # include <stdio.h>
44 # include <string.h>
45 # include <ctype.h>	/* tolower(), ... */
46 # include <unistd.h>	/* link(), unlink(), ... */
47 # include <stdlib.h>
48 # include <sys/types.h>
49 # include <sys/time.h>
50 # include <sys/stat.h>
51 # include <dirent.h>
52 # include <assert.h>
53 #ifdef HAVE_CONFIG_H
54 # include <config.h>
55 #endif
56 # include "config_zkt.h"
57 # include "debug.h"
58 # include "domaincmp.h"
59 # include "misc.h"
60 # include "zconf.h"
61 #define	extern
62 # include "dki.h"
63 #undef	extern
64 
65 /*****************************************************************
66 **	private (static) function declaration and definition
67 *****************************************************************/
68 static	char	dki_estr[255+1];
69 
70 static	dki_t	*dki_alloc ()
71 {
72 	dki_estr[0] = '\0';
73 	dki_t	*dkp = malloc (sizeof (dki_t));
74 
75 	if ( (dkp = malloc (sizeof (dki_t))) )
76 	{
77 		memset (dkp, 0, sizeof (dki_t));
78 		return dkp;
79 	}
80 
81 	snprintf (dki_estr, sizeof (dki_estr),
82 			"dki_alloc: Out of memory");
83 	return NULL;
84 }
85 
86 static	int	dki_readfile (FILE *fp, dki_t *dkp)
87 {
88 	int	algo,	flags,	type;
89 	int	c;
90 	char	*p;
91 	char	buf[4095+1];
92 	char	tag[25+1];
93 	char	val[14+1];	/* e.g. "YYYYMMDDhhmmss" | "60d" */
94 
95 	assert (dkp != NULL);
96 	assert (fp != NULL);
97 
98 	while ( (c = getc (fp)) == ';' )	/* line start with comment ? */
99 	{
100 		tag[0] = val[0] = '\0';
101 		if ( (c = getc (fp)) == '%' )	/* special comment? */
102 		{
103 			while ( (c = getc (fp)) == ' ' || c == '\t' )
104 				;
105 			ungetc (c, fp);
106 			/* then try to read in the creation, expire and lifetime */
107 			if ( fscanf (fp, "%25[a-zA-Z]=%14s", tag, val) == 2 )
108 			{
109 				dbg_val2 ("dki_readfile: tag=%s val=%s \n", tag, val);
110 				switch ( tolower (tag[0]) )
111 				{
112 				case 'g': dkp->gentime = timestr2time (val);	break;
113 				case 'e': dkp->exptime = timestr2time (val);	break;
114 				case 'l': dkp->lifetime = atoi (val) * DAYSEC;	break;
115 				}
116 			}
117 		}
118 		else
119 			ungetc (c, fp);
120 		while ( (c = getc (fp)) != EOF && c != '\n' )	/* eat up rest of the line */
121 			;
122 	}
123 	ungetc (c, fp);	/* push back last char */
124 
125 	if ( fscanf (fp, "%4095s", buf) != 1 )	/* read label */
126 		return -1;
127 
128 	if ( strcmp (buf, dkp->name) != 0 )
129 		return -2;
130 
131 #if defined(TTL_IN_KEYFILE_ALLOWED) && TTL_IN_KEYFILE_ALLOWED
132 	/* skip optional TTL value */
133 	while ( (c = getc (fp)) != EOF && isspace (c) )	/* skip spaces */
134 		;
135 	if ( isdigit (c) )				/* skip ttl */
136 		fscanf (fp, "%*d");
137 	else
138 		ungetc (c, fp);				/* oops, no ttl */
139 #endif
140 
141 	if ( (c = fscanf (fp, " IN DNSKEY %d %d %d", &flags, &type, &algo)) != 3 &&
142 	     (c = fscanf (fp, "KEY %d %d %d", &flags, &type, &algo)) != 3 )
143 		return -3;
144 	if ( type != 3 || algo != dkp->algo )
145 		return -4;		/* no DNSKEY or algorithm mismatch */
146 	if ( ((flags >> 8) & 0xFF) != 01 )
147 		return -5;		/* no ZONE key */
148 	dkp->flags = flags;
149 
150 	if ( fgets (buf, sizeof buf, fp) == NULL || buf[0] == '\0' )
151 		return -6;
152 	p = buf + strlen (buf);
153 	*--p = '\0';		/* delete trailing \n */
154 	/* delete leading ws */
155 	for ( p = buf; *p  && isspace (*p); p++ )
156 		;
157 
158 	dkp->pubkey = strdup (p);
159 
160 	return 0;
161 }
162 
163 static	int	dki_writeinfo (const dki_t *dkp, const char *path)
164 {
165 	FILE	*fp;
166 
167 	assert (dkp != NULL);
168 	assert (path != NULL && path[0] != '\0');
169 
170 	if ( (fp = fopen (path, "w")) == NULL )
171 		return 0;
172 	dbg_val1 ("dki_writeinfo %s\n", path);
173 	if ( dki_prt_dnskey_raw (dkp, fp) == 0 )
174 		return 0;
175 	fclose (fp);
176 	touch (path, dkp->time);	/* restore time of key file */
177 
178 	return 1;
179 }
180 
181 static	int	dki_setstat (dki_t *dkp, int status, int preserve_time);
182 
183 /*****************************************************************
184 **	public function definition
185 *****************************************************************/
186 
187 /*****************************************************************
188 **	dki_free ()
189 *****************************************************************/
190 void	dki_free (dki_t *dkp)
191 {
192 	assert (dkp != NULL);
193 
194 	if ( dkp->pubkey )
195 		free (dkp->pubkey);
196 	free (dkp);
197 }
198 
199 /*****************************************************************
200 **	dki_freelist ()
201 *****************************************************************/
202 void	dki_freelist (dki_t **listp)
203 {
204 	dki_t	*curr;
205 	dki_t	*next;
206 
207 	assert (listp != NULL);
208 
209 	curr = *listp;
210 	while ( curr )
211 	{
212 		next = curr->next;
213 		dki_free (curr);
214 		curr = next;
215 	}
216 	if ( *listp )
217 		*listp = NULL;
218 }
219 
220 #if defined(USE_TREE) && USE_TREE
221 /*****************************************************************
222 **	dki_tfree ()
223 *****************************************************************/
224 void	dki_tfree (dki_t **tree)
225 {
226 	assert (tree != NULL);
227 	// TODO: tdestroy is a GNU extension
228 	// tdestroy (*tree, dki_free);
229 }
230 #endif
231 
232 # define	KEYGEN_COMPMODE	"-C -q "	/* this is the compability mode needed since BIND 9.7 */
233 /*****************************************************************
234 **	dki_new ()
235 **	create new keyfile
236 **	allocate memory for new dki key and init with keyfile
237 *****************************************************************/
238 dki_t	*dki_new (const char *dir, const char *name, int ksk, int algo, int bitsize, const char *rfile, int lf_days)
239 {
240 	char	cmdline[511+1];
241 	char	fname[254+1];
242 	char	randfile[254+1];
243 	FILE	*fp;
244 	int	len;
245 	char	*flag = "";
246 	char    *expflag = "";
247 	dki_t	*new;
248 
249 	if ( ksk )
250 		flag = "-f KSK";
251 
252 	randfile[0] = '\0';
253 	if ( rfile && *rfile )
254 		snprintf (randfile, sizeof (randfile), "-r %.250s ", rfile);
255 
256 #if defined(BIND_VERSION) && BIND_VERSION < 90902
257 	if ( algo == DK_ALGO_RSA || algo == DK_ALGO_RSASHA1 || algo == DK_ALGO_RSASHA256 || algo == DK_ALGO_RSASHA512 )
258 		expflag = "-e ";
259 #endif
260 	if ( dir && *dir )
261 		snprintf (cmdline, sizeof (cmdline), "cd %s ; %s %s%s%s-n ZONE -a %s -b %d %s %s",
262 			dir, KEYGENCMD, KEYGEN_COMPMODE, randfile, expflag, dki_algo2str(algo), bitsize, flag, name);
263 	else
264 		snprintf (cmdline, sizeof (cmdline), "%s %s%s%s-n ZONE -a %s -b %d %s %s",
265 			KEYGENCMD, KEYGEN_COMPMODE, randfile, expflag, dki_algo2str(algo), bitsize, flag, name);
266 
267 	dbg_msg (cmdline);
268 
269 	if ( (fp = popen (cmdline, "r")) == NULL || fgets (fname, sizeof fname, fp) == NULL )
270 		return NULL;
271 	pclose (fp);
272 
273 	len = strlen (fname) - 1;
274 	if ( len >= 0 && fname[len] == '\n' )
275 		fname[len] = '\0';
276 
277 	new = dki_read (dir, fname);
278 	if ( new )
279 		dki_setlifetime (new, lf_days);	/* sets gentime + proposed lifetime */
280 
281 	return new;
282 }
283 
284 /*****************************************************************
285 **	dki_read ()
286 **	read key from file 'filename' (independed of the extension)
287 *****************************************************************/
288 dki_t	*dki_read (const char *dirname, const char *filename)
289 {
290 	dki_t	*dkp;
291 	FILE	*fp;
292 	struct	stat	st;
293 	int	len;
294 	int	err;
295 	char	fname[MAX_FNAMESIZE+1];
296 	char	path[MAX_PATHSIZE+1];
297 
298 	dki_estr[0] = '\0';
299 	if ( (dkp = dki_alloc ()) == NULL )
300 		return (NULL);
301 
302 	len = sizeof (fname) - 1;
303 	fname[len] = '\0';
304 	strncpy (fname, filename, len);
305 
306 	len = strlen (fname);			/* delete extension */
307 	if ( len > 4 && strcmp (&fname[len - 4], DKI_KEY_FILEEXT) == 0 )
308 		fname[len - 4] = '\0';
309 	else if ( len > 10 && strcmp (&fname[len - 10], DKI_PUB_FILEEXT) == 0 )
310 		fname[len - 10] = '\0';
311 	else if ( len > 8 && strcmp (&fname[len - 8], DKI_ACT_FILEEXT) == 0 )
312 		fname[len - 8] = '\0';
313 	else if ( len > 12 && strcmp (&fname[len - 12], DKI_DEP_FILEEXT) == 0 )
314 		fname[len - 12] = '\0';
315 	dbg_line ();
316 
317 	assert (strlen (dirname)+1 < sizeof (dkp->dname));
318 	strcpy (dkp->dname, dirname);
319 
320 	assert (strlen (fname)+1 < sizeof (dkp->fname));
321 	strcpy (dkp->fname, fname);
322 	dbg_line ();
323 	if ( sscanf (fname, "K%254[^+]+%hd+%d", dkp->name, &dkp->algo, &dkp->tag) != 3 )
324 	{
325 		snprintf (dki_estr, sizeof (dki_estr),
326 			"dki_read: Filename don't match expected format (%s)", fname);
327 		return (NULL);
328 	}
329 
330 	pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
331 	dbg_val ("dki_read: path \"%s\"\n", path);
332 	if ( (fp = fopen (path, "r")) == NULL )
333 	{
334 		snprintf (dki_estr, sizeof (dki_estr),
335 			"dki_read: Can\'t open file \"%s\" for reading", path);
336 		return (NULL);
337 	}
338 
339 	dbg_line ();
340 	if ( (err = dki_readfile (fp, dkp)) != 0 )
341 	{
342 		dbg_line ();
343 		snprintf (dki_estr, sizeof (dki_estr),
344 			"dki_read: Can\'t read key from file %s (errno %d)", path, err);
345 		fclose (fp);
346 		return (NULL);
347 	}
348 
349 	dbg_line ();
350 	if ( fstat (fileno(fp), &st) )
351 	{
352 		snprintf (dki_estr, sizeof (dki_estr),
353 			"dki_read: Can\'t stat file %s", fname);
354 		return (NULL);
355 	}
356 	dkp->time = st.st_mtime;
357 
358 	dbg_line ();
359 	pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_ACT_FILEEXT);
360 	if ( fileexist (path) )
361 	{
362 		if ( dki_isrevoked (dkp) )
363 			dkp->status = DKI_REV;
364 		else
365 			dkp->status = DKI_ACT;
366 	}
367 	else
368 	{
369 		pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_PUB_FILEEXT);
370 		if ( fileexist (path) )
371 			dkp->status = DKI_PUB;
372 		else
373 		{
374 			pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_DEP_FILEEXT);
375 			if ( fileexist (path) )
376 				dkp->status = DKI_DEP;
377 			else
378 				dkp->status = DKI_SEP;
379 		}
380 	}
381 
382 	dbg_line ();
383 	fclose (fp);
384 
385 	dbg_line ();
386 	return dkp;
387 }
388 
389 /*****************************************************************
390 **	dki_readdir ()
391 **	read key files from directory 'dir' and, if recursive is
392 **	true, from all directorys below that.
393 *****************************************************************/
394 int	dki_readdir (const char *dir, dki_t **listp, int recursive)
395 {
396 	dki_t	*dkp;
397 	DIR	*dirp;
398 	struct  dirent  *dentp;
399 	char	path[MAX_PATHSIZE+1];
400 
401 	dbg_val ("directory: opendir(%s)\n", dir);
402 	if ( (dirp = opendir (dir)) == NULL )
403 		return 0;
404 
405 	while ( (dentp = readdir (dirp)) != NULL )
406 	{
407 		if ( is_dotfilename (dentp->d_name) )
408 			continue;
409 
410 		dbg_val ("directory: check %s\n", dentp->d_name);
411 		pathname (path, sizeof (path), dir, dentp->d_name, NULL);
412 		if ( is_directory (path) && recursive )
413 		{
414 			dbg_val ("directory: recursive %s\n", path);
415 			dki_readdir (path, listp, recursive);
416 		}
417 		else if ( is_keyfilename (dentp->d_name) )
418 			if ( (dkp = dki_read (dir, dentp->d_name)) )
419 				dki_add (listp, dkp);
420 	}
421 	closedir (dirp);
422 	return 1;
423 }
424 
425 /*****************************************************************
426 **	dki_setstatus_preservetime ()
427 **	set status of key and change extension to
428 **	".published", ".private" or ".depreciated"
429 *****************************************************************/
430 int	dki_setstatus_preservetime (dki_t *dkp, int status)
431 {
432 	return dki_setstat (dkp, status, 1);
433 }
434 
435 /*****************************************************************
436 **	dki_setstatus ()
437 **	set status of key and change extension to
438 **	".published", ".private" or ".depreciated"
439 *****************************************************************/
440 int	dki_setstatus (dki_t *dkp, int status)
441 {
442 	return dki_setstat (dkp, status, 0);
443 }
444 
445 /*****************************************************************
446 **	dki_setstat ()
447 **	low level function of dki_setstatus and dki_setstatus_preservetime
448 *****************************************************************/
449 static	int	dki_setstat (dki_t *dkp, int status, int preserve_time)
450 {
451 	char	frompath[MAX_PATHSIZE+1];
452 	char	topath[MAX_PATHSIZE+1];
453 	time_t	totime;
454 
455 	if ( dkp == NULL )
456 		return 0;
457 
458 	status = tolower (status);
459 	switch ( dkp->status )	/* look at old status */
460 	{
461 	case 'r':
462 		if ( status == 'r' )
463 			return 1;
464 		break;
465 	case 'a':
466 		if ( status == 'a' )
467 			return 1;
468 		pathname (frompath, sizeof (frompath), dkp->dname, dkp->fname, DKI_ACT_FILEEXT);
469 		break;
470 	case 'd':
471 		if ( status == 'd' )
472 			return 1;
473 		pathname (frompath, sizeof (frompath), dkp->dname, dkp->fname, DKI_DEP_FILEEXT);
474 		break;
475 	case 'p':	/* or 's' */
476 		if ( status == 'p' || status == 's' )
477 			return 1;
478 		pathname (frompath, sizeof (frompath), dkp->dname, dkp->fname, DKI_PUB_FILEEXT);
479 		break;
480 	default:
481 		/* TODO: set error code */
482 		return 0;
483 	}
484 
485 	dbg_val ("dki_setstat: \"%s\"\n", frompath);
486 	dbg_val ("dki_setstat: to status \"%c\"\n", status);
487 
488 	/* a state change could result in different things: */
489 	/* 1) write a new keyfile when the REVOKE bit is set or unset */
490 	if ( status == 'r' || (status == 'a' && dki_isrevoked (dkp)) )
491 	{
492 		pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
493 
494 		if ( status == 'r' )
495 			dki_setflag (dkp, DK_FLAG_REVOKE);	/* set REVOKE bit */
496 		else
497 			dki_unsetflag (dkp, DK_FLAG_REVOKE);	/* clear REVOKE bit */
498 
499 
500 		dki_writeinfo (dkp, topath);	/* ..and write it to the key file */
501 
502 		if ( !preserve_time )
503 			touch (topath, time (NULL));
504 
505 		return 0;
506 	}
507 
508 
509 	/* 2) change the filename of the private key in all other cases */
510 	totime = 0L;
511 	if ( preserve_time )
512 		totime = file_mtime (frompath);    /* get original timestamp */
513 	topath[0] = '\0';
514 	switch ( status )
515 	{
516 	case 'a':
517 		pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_ACT_FILEEXT);
518 		break;
519 	case 'd':
520 		pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_DEP_FILEEXT);
521 		break;
522 	case 's':		/* standby means a "published KSK" */
523 		if ( !dki_isksk (dkp) )
524 			return 2;
525 		status = 'p';
526 		/* fall through */
527 	case 'p':
528 		pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_PUB_FILEEXT);
529 		break;
530 	}
531 
532 	if ( topath[0] )
533 	{
534 		dbg_val ("dki_setstat: to  \"%s\"\n", topath);
535 		if ( link (frompath, topath) == 0 )
536 			unlink (frompath);
537 		dkp->status = status;
538 		if ( !totime )
539 			totime = time (NULL);	/* set .key file to current time */
540 		pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
541 		touch (topath, totime);	/* store/restore time of status change */
542 	}
543 
544 	return 0;
545 }
546 
547 /*****************************************************************
548 **	dki_remove ()
549 **	rename files associated with key, so that the keys are not
550 **	recognized by the zkt tools e.g.
551 **	Kdo.ma.in.+001+12345.key ==> kdo.ma.in.+001+12345.key
552 **	(second one starts with a lower case 'k')
553 *****************************************************************/
554 dki_t	*dki_remove (dki_t *dkp)
555 {
556 	char	path[MAX_PATHSIZE+1];
557 	char	newpath[MAX_PATHSIZE+1];
558 	char	newfile[MAX_FNAMESIZE+1];
559 	dki_t	*next;
560 	const	char	**pext;
561 	static	const	char	*ext[] = {
562 		DKI_KEY_FILEEXT, DKI_PUB_FILEEXT,
563 		DKI_ACT_FILEEXT, DKI_DEP_FILEEXT,
564 		NULL
565 	};
566 
567 	if ( dkp == NULL )
568 		return NULL;
569 
570 	strncpy (newfile, dkp->fname, sizeof (newfile));
571 	*newfile = tolower (*newfile);
572 	for ( pext = ext; *pext; pext++ )
573 	{
574 		pathname (path, sizeof (path), dkp->dname, dkp->fname, *pext);
575 		if ( fileexist (path) )
576 		{
577 			pathname (newpath, sizeof (newpath), dkp->dname, newfile, *pext);
578 
579 			dbg_val2 ("dki_remove: %s ==> %s \n", path, newpath);
580 			rename (path, newpath);
581 		}
582 	}
583 	next = dkp->next;
584 	dki_free (dkp);
585 
586 	return next;
587 }
588 
589 /*****************************************************************
590 **	dki_destroy ()
591 **	delete files associated with key and free allocated memory
592 *****************************************************************/
593 dki_t	*dki_destroy (dki_t *dkp)
594 {
595 	char	path[MAX_PATHSIZE+1];
596 	dki_t	*next;
597 	const	char	**pext;
598 	static	const	char	*ext[] = {
599 		DKI_KEY_FILEEXT, DKI_PUB_FILEEXT,
600 		DKI_ACT_FILEEXT, DKI_DEP_FILEEXT,
601 		NULL
602 	};
603 
604 	if ( dkp == NULL )
605 		return NULL;
606 
607 	for ( pext = ext; *pext; pext++ )
608 	{
609 		pathname (path, sizeof (path), dkp->dname, dkp->fname, *pext);
610 		if ( fileexist (path) )
611 		{
612 			dbg_val ("dki_remove: %s \n", path);
613 			unlink (path);
614 		}
615 	}
616 	next = dkp->next;
617 	dki_free (dkp);
618 
619 	return next;
620 }
621 
622 /*****************************************************************
623 **	dki_algo2str ()
624 **	return a string describing the key algorithm
625 *****************************************************************/
626 char	*dki_algo2str (int algo)
627 {
628 	switch ( algo )
629 	{
630 	case DK_ALGO_RSA:		return ("RSAMD5");
631 	case DK_ALGO_DH:		return ("DH");
632 	case DK_ALGO_DSA:		return ("DSA");
633 	case DK_ALGO_EC:		return ("EC");
634 	case DK_ALGO_RSASHA1:		return ("RSASHA1");
635 	case DK_ALGO_NSEC3DSA:		return ("NSEC3DSA");
636 	case DK_ALGO_NSEC3RSASHA1:	return ("NSEC3RSASHA1");
637 	case DK_ALGO_RSASHA256:		return ("RSASHA256");
638 	case DK_ALGO_RSASHA512:		return ("RSASHA512");
639 	}
640 	return ("unknown");
641 }
642 
643 /*****************************************************************
644 **	dki_algo2sstr ()
645 **	return a short string describing the key algorithm
646 *****************************************************************/
647 char	*dki_algo2sstr (int algo)
648 {
649 	switch ( algo )
650 	{
651 	case DK_ALGO_RSA:		return ("RSAMD5");
652 	case DK_ALGO_DH:		return ("DH");
653 	case DK_ALGO_DSA:		return ("DSA");
654 	case DK_ALGO_EC:		return ("EC");
655 	case DK_ALGO_RSASHA1:		return ("RSASHA1");
656 	case DK_ALGO_NSEC3DSA:		return ("N3DSA");
657 	case DK_ALGO_NSEC3RSASHA1:	return ("N3RSA1");
658 	case DK_ALGO_RSASHA256:		return ("RSASHA2");
659 	case DK_ALGO_RSASHA512:		return ("RSASHA5");
660 	}
661 	return ("unknown");
662 }
663 
664 /*****************************************************************
665 **	dki_geterrstr ()
666 **	return error string
667 *****************************************************************/
668 const	char	*dki_geterrstr ()
669 {
670 	return dki_estr;
671 }
672 
673 /*****************************************************************
674 **	dki_prt_dnskey ()
675 *****************************************************************/
676 int	dki_prt_dnskey (const dki_t *dkp, FILE *fp)
677 {
678 	return dki_prt_dnskeyttl (dkp, fp, 0);
679 }
680 
681 /*****************************************************************
682 **	dki_prt_dnskeyttl ()
683 *****************************************************************/
684 int	dki_prt_dnskeyttl (const dki_t *dkp, FILE *fp, int ttl)
685 {
686 	char	*p;
687 
688 	if ( dkp == NULL )
689 		return 0;
690 
691 	fprintf (fp, "%s ", dkp->name);
692 	if ( ttl > 0 )
693 		fprintf (fp, "%d ", ttl);
694 	fprintf (fp, "IN DNSKEY  ");
695 	fprintf (fp, "%d 3 %d (", dkp->flags, dkp->algo);
696 	fprintf (fp, "\n\t\t\t");
697 	for ( p = dkp->pubkey; *p ; p++ )
698 		if ( *p == ' ' )
699 			fprintf (fp, "\n\t\t\t");
700 		else
701 			putc (*p, fp);
702 	fprintf (fp, "\n\t\t");
703 	if ( dki_isrevoked (dkp) )
704 		fprintf (fp, ") ; key id = %u (original key id = %u)", (dkp->tag + 128) % 65535, dkp->tag);
705 	else
706 		fprintf (fp, ") ; key id = %u", dkp->tag);
707 	fprintf (fp, "\n");
708 
709 	return 1;
710 }
711 
712 /*****************************************************************
713 **	dki_prt_dnskey_raw ()
714 *****************************************************************/
715 int	dki_prt_dnskey_raw (const dki_t *dkp, FILE *fp)
716 {
717 	int	days;
718 
719 	if ( dkp == NULL )
720 		return 0;
721 
722 	if ( dkp->gentime  )
723 		fprintf (fp, ";%%\tgenerationtime=%s\n", time2isostr (dkp->gentime, 's'));
724 	if ( (days = dki_lifetimedays (dkp)) )
725 		fprintf (fp, ";%%\tlifetime=%dd\n", days);
726 	if ( dkp->exptime  )
727 		fprintf (fp, ";%%\texpirationtime=%s\n", time2isostr (dkp->exptime, 's'));
728 
729 	fprintf (fp, "%s ", dkp->name);
730 #if 0
731 	if ( ttl > 0 )
732 		fprintf (fp, "%d ", ttl);
733 #endif
734 	fprintf (fp, "IN DNSKEY  ");
735 	fprintf (fp, "%d 3 %d ", dkp->flags, dkp->algo);
736 	fprintf (fp, "%s\n", dkp->pubkey);
737 
738 	return 1;
739 }
740 
741 /*****************************************************************
742 **	dki_prt_comment ()
743 *****************************************************************/
744 int	dki_prt_comment (const dki_t *dkp, FILE *fp)
745 {
746 	int	len = 0;
747 
748 	if ( dkp == NULL )
749 		return len;
750 	len += fprintf (fp, "; %s  ", dkp->name);
751 	len += fprintf (fp, "tag=%u  ", dkp->tag);
752 	len += fprintf (fp, "algo=%s  ", dki_algo2str(dkp->algo));
753 	len += fprintf (fp, "generated %s\n", time2str (dkp->time, 's'));
754 
755 	return len;
756 }
757 
758 /*****************************************************************
759 **	dki_prt_trustedkey ()
760 *****************************************************************/
761 int	dki_prt_trustedkey (const dki_t *dkp, FILE *fp)
762 {
763 	char	*p;
764 	int	spaces;
765 	int	len = 0;
766 
767 	if ( dkp == NULL )
768 		return len;
769 	len += fprintf (fp, "\"%s\"  ", dkp->name);
770 	spaces = 22 - (strlen (dkp->name) + 3);
771 	len += fprintf (fp, "%*s", spaces > 0 ? spaces : 0 , " ");
772 	len += fprintf (fp, "%d 3 %d ", dkp->flags, dkp->algo);
773 	if ( spaces < 0 )
774 		len += fprintf (fp, "\n\t\t\t%7s", " ");
775 	len += fprintf (fp, "\"");
776 	for ( p = dkp->pubkey; *p ; p++ )
777 		if ( *p == ' ' )
778 			len += fprintf (fp, "\n\t\t\t\t");
779 		else
780 			putc (*p, fp), len += 1;
781 
782 	if ( dki_isrevoked (dkp) )
783 		len += fprintf (fp, "\" ; # key id = %u (original key id = %u)\n\n", (dkp->tag + 128) % 65535, dkp->tag);
784 	else
785 		len += fprintf (fp, "\" ; # key id = %u\n\n", dkp->tag);
786 	return len;
787 }
788 
789 /*****************************************************************
790 **	dki_prt_managedkey ()
791 *****************************************************************/
792 int	dki_prt_managedkey (const dki_t *dkp, FILE *fp)
793 {
794 	char	*p;
795 	int	spaces;
796 	int	len = 0;
797 
798 	if ( dkp == NULL )
799 		return len;
800 	len += fprintf (fp, "\"%s\"  ", dkp->name);
801 	spaces = 22 - (strlen (dkp->name) + 3);
802 	len += fprintf (fp, "initial-key  ");
803 	spaces -= 13;
804 	len += fprintf (fp, "%*s", spaces > 0 ? spaces : 0 , " ");
805 	len += fprintf (fp, "%d 3 %d ", dkp->flags, dkp->algo);
806 	if ( spaces < 0 )
807 		len += fprintf (fp, "\n\t\t\t%7s", " ");
808 	len += fprintf (fp, "\"");
809 	for ( p = dkp->pubkey; *p ; p++ )
810 		if ( *p == ' ' )
811 			len += fprintf (fp, "\n\t\t\t\t");
812 		else
813 			putc (*p, fp), len += 1;
814 
815 	if ( dki_isrevoked (dkp) )
816 		len += fprintf (fp, "\" ; # key id = %u (original key id = %u)\n\n", (dkp->tag + 128) % 65535, dkp->tag);
817 	else
818 		len += fprintf (fp, "\" ; # key id = %u\n\n", dkp->tag);
819 	return len;
820 }
821 
822 
823 /*****************************************************************
824 **	dki_cmp () 	return <0 | 0 | >0
825 *****************************************************************/
826 int	dki_cmp (const dki_t *a, const dki_t *b)
827 {
828 	int	res;
829 
830 	if ( a == NULL ) return -1;
831 	if ( b == NULL ) return 1;
832 
833 	/* sort by domain name, */
834 	if ( (res = domaincmp (a->name, b->name)) != 0 )
835 		return res;
836 
837 	/* then by key type, */
838 	if ( (res = dki_isksk (b) - dki_isksk (a)) != 0 )
839 		return res;
840 
841 	/* and last by creation time,  */
842 	return (ulong)a->time - (ulong)b->time;
843 }
844 
845 #if defined(USE_TREE) && USE_TREE
846 /*****************************************************************
847 **	dki_allcmp () 	return <0 | 0 | >0
848 *****************************************************************/
849 int	dki_allcmp (const dki_t *a, const dki_t *b)
850 {
851 	int	res;
852 
853 	if ( a == NULL ) return -1;
854 	if ( b == NULL ) return 1;
855 
856 // fprintf (stderr, "dki_allcmp %s, %s)\n", a->name, b->name);
857 	/* sort by domain name, */
858 	if ( (res = domaincmp (a->name, b->name)) != 0 )
859 		return res;
860 
861 	/* then by key type, */
862 	if ( (res = dki_isksk (b) - dki_isksk (a)) != 0 )
863 		return res;
864 
865 	/* creation time,  */
866 	if ( (res = (ulong)a->time - (ulong)b->time) != 0 )
867 		return res;
868 
869 	/* and last by tag */
870 	return a->tag - b->tag;
871 }
872 
873 /*****************************************************************
874 **	dki_namecmp () 	return <0 | 0 | >0
875 *****************************************************************/
876 int	dki_namecmp (const dki_t *a, const dki_t *b)
877 {
878 	if ( a == NULL ) return -1;
879 	if ( b == NULL ) return 1;
880 
881 	return domaincmp (a->name, b->name);
882 }
883 
884 /*****************************************************************
885 **	dki_revnamecmp () 	return <0 | 0 | >0
886 *****************************************************************/
887 int	dki_revnamecmp (const dki_t *a, const dki_t *b)
888 {
889 	if ( a == NULL ) return -1;
890 	if ( b == NULL ) return 1;
891 
892 	return domaincmp_dir (a->name, b->name, 0);
893 }
894 
895 /*****************************************************************
896 **	dki_tagcmp () 	return <0 | 0 | >0
897 *****************************************************************/
898 int	dki_tagcmp (const dki_t *a, const dki_t *b)
899 {
900 	if ( a == NULL ) return -1;
901 	if ( b == NULL ) return 1;
902 
903 	return a->tag - b->tag;
904 }
905 #endif
906 
907 /*****************************************************************
908 **	dki_timecmp ()
909 *****************************************************************/
910 int	dki_timecmp (const dki_t *a, const dki_t *b)
911 {
912 	if ( a == NULL ) return -1;
913 	if ( b == NULL ) return 1;
914 
915 	return ((ulong)a->time - (ulong)b->time);
916 }
917 
918 /*****************************************************************
919 **	dki_algo ()	return the algorithm of the key
920 *****************************************************************/
921 time_t	dki_algo (const dki_t *dkp)
922 {
923 	assert (dkp != NULL);
924 	return (dkp->algo);
925 }
926 
927 /*****************************************************************
928 **	dki_time ()	return the timestamp of the key
929 *****************************************************************/
930 time_t	dki_time (const dki_t *dkp)
931 {
932 	assert (dkp != NULL);
933 	return (dkp->time);
934 }
935 
936 /*****************************************************************
937 **	dki_exptime ()	return the expiration timestamp of the key
938 *****************************************************************/
939 time_t	dki_exptime (const dki_t *dkp)
940 {
941 	assert (dkp != NULL);
942 	return (dkp->exptime);
943 }
944 
945 /*****************************************************************
946 **	dki_lifetime (dkp)	return the lifetime of the key in sec!
947 *****************************************************************/
948 time_t	dki_lifetime (const dki_t *dkp)
949 {
950 	assert (dkp != NULL);
951 	return (dkp->lifetime);
952 }
953 
954 /*****************************************************************
955 **	dki_lifetimedays (dkp)	return the lifetime of the key in days!
956 *****************************************************************/
957 ushort	dki_lifetimedays (const dki_t *dkp)
958 {
959 	assert (dkp != NULL);
960 	return (dkp->lifetime / DAYSEC);
961 }
962 
963 /*****************************************************************
964 **	dki_gentime (dkp)	return the generation timestamp of the key
965 *****************************************************************/
966 time_t	dki_gentime (const dki_t *dkp)
967 {
968 	assert (dkp != NULL);
969 	return (dkp->gentime > 0L ? dkp->gentime: dkp->time);
970 }
971 
972 /*****************************************************************
973 **	dki_setlifetime (dkp, int days)
974 **	set the lifetime in days (and also the gentime if not set)
975 **	return the old lifetime of the key in days!
976 *****************************************************************/
977 ushort	dki_setlifetime (dki_t *dkp, int days)
978 {
979 	ulong	lifetsec;
980 	char	path[MAX_PATHSIZE+1];
981 
982 	assert (dkp != NULL);
983 
984 	lifetsec = dkp->lifetime;		/* old lifetime */
985 	dkp->lifetime = days * DAYSEC;		/* set new lifetime */
986 
987 	dbg_val1 ("dki_setlifetime (%d)\n", days);
988 	if ( lifetsec == 0 )	/* initial setup (old lifetime was zero)? */
989 		dkp->gentime = dkp->time;
990 
991 	pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
992 	dki_writeinfo (dkp, path);
993 
994 	return (lifetsec / DAYSEC);
995 }
996 
997 /*****************************************************************
998 **	dki_setexptime (dkp, time_t sec)
999 **	set the expiration time of the key in seconds since the epoch
1000 **	return the old exptime
1001 *****************************************************************/
1002 time_t	dki_setexptime (dki_t *dkp, time_t sec)
1003 {
1004 	char	path[MAX_PATHSIZE+1];
1005 	time_t	oldexptime;
1006 
1007 	assert (dkp != NULL);
1008 
1009 	dbg_val1 ("dki_setexptime (%ld)\n", sec);
1010 	oldexptime = dkp->exptime;
1011 	dkp->exptime = sec;
1012 
1013 	pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
1014 	dki_writeinfo (dkp, path);
1015 
1016 #if 0	/* not necessary ? */
1017 	touch (path, time (NULL));
1018 #endif
1019 	return (oldexptime);
1020 }
1021 
1022 /*****************************************************************
1023 **	dki_age ()	return age of key in seconds since 'curr'
1024 *****************************************************************/
1025 int	dki_age (const dki_t *dkp, time_t curr)
1026 {
1027 	assert (dkp != NULL);
1028 	return ((ulong)curr - (ulong)dkp->time);
1029 }
1030 
1031 /*****************************************************************
1032 **	dki_getflag ()	return the flags field of a key
1033 *****************************************************************/
1034 dk_flag_t	dki_getflag (const dki_t *dkp, time_t curr)
1035 {
1036 	return dkp->flags;
1037 }
1038 
1039 /*****************************************************************
1040 **	dki_setflag ()	set a flag of a key
1041 *****************************************************************/
1042 dk_flag_t	dki_setflag (dki_t *dkp, dk_flag_t flag)
1043 {
1044 	return dkp->flags |= (ushort)flag;
1045 }
1046 
1047 /*****************************************************************
1048 **	dki_unsetflag ()	unset a flag of a key
1049 *****************************************************************/
1050 dk_flag_t	dki_unsetflag (dki_t *dkp, dk_flag_t flag)
1051 {
1052 	return dkp->flags &= ~((ushort)flag);
1053 }
1054 
1055 /*****************************************************************
1056 **	dki_isksk ()
1057 *****************************************************************/
1058 int	dki_isksk (const dki_t *dkp)
1059 {
1060 	assert (dkp != NULL);
1061 	return (dkp->flags & DK_FLAG_KSK) == DK_FLAG_KSK;
1062 }
1063 
1064 /*****************************************************************
1065 **	dki_isrevoked ()
1066 *****************************************************************/
1067 int	dki_isrevoked (const dki_t *dkp)
1068 {
1069 	assert (dkp != NULL);
1070 	return (dkp->flags & DK_FLAG_REVOKE) == DK_FLAG_REVOKE;
1071 }
1072 
1073 /*****************************************************************
1074 **	dki_isdepreciated ()
1075 *****************************************************************/
1076 int	dki_isdepreciated (const dki_t *dkp)
1077 {
1078 	return dki_status (dkp) == DKI_DEPRECIATED;
1079 }
1080 
1081 /*****************************************************************
1082 **	dki_isactive ()
1083 *****************************************************************/
1084 int	dki_isactive (const dki_t *dkp)
1085 {
1086 	return dki_status (dkp) == DKI_ACTIVE;
1087 }
1088 
1089 /*****************************************************************
1090 **	dki_ispublished ()
1091 *****************************************************************/
1092 int	dki_ispublished (const dki_t *dkp)
1093 {
1094 	return dki_status (dkp) == DKI_PUBLISHED;
1095 }
1096 
1097 
1098 /*****************************************************************
1099 **	dki_status ()	return key status
1100 *****************************************************************/
1101 dk_status_t	dki_status (const dki_t *dkp)
1102 {
1103 	assert (dkp != NULL);
1104 	return (dkp->status);
1105 }
1106 
1107 /*****************************************************************
1108 **	dki_statusstr ()	return key status as string
1109 *****************************************************************/
1110 const	char	*dki_statusstr (const dki_t *dkp)
1111 {
1112 	assert (dkp != NULL);
1113 	switch ( dkp->status )
1114 	{
1115 	case DKI_ACT:	return "active";
1116 	case DKI_PUB:   if ( dki_isksk (dkp) )
1117 				return "standby";
1118 			else
1119 				return "published";
1120 	case DKI_DEP:   return "depreciated";
1121 	case DKI_REV:   return "revoked";
1122 	case DKI_SEP:   return "sep";
1123 	}
1124 	return "unknown";
1125 }
1126 
1127 /*****************************************************************
1128 **	dki_add ()	add a key to the given list
1129 *****************************************************************/
1130 dki_t	*dki_add (dki_t **list, dki_t *new)
1131 {
1132 	dki_t	*curr;
1133 	dki_t	*last;
1134 
1135 	if ( list == NULL )
1136 		return NULL;
1137 	if ( new == NULL )
1138 		return *list;
1139 
1140 	last = curr = *list;
1141 	while ( curr && dki_cmp (curr, new) < 0 )
1142 	{
1143 		last = curr;
1144 		curr = curr->next;
1145 	}
1146 
1147 	if ( curr == *list )	/* add node at start of list */
1148 		*list = new;
1149 	else			/* add node at end or between two nodes */
1150 		last->next = new;
1151 	new->next = curr;
1152 
1153 	return *list;
1154 }
1155 
1156 /*****************************************************************
1157 **	dki_search ()	search a key with the given tag, or the first
1158 **			occurence of a key with the given name
1159 *****************************************************************/
1160 const dki_t	*dki_search (const dki_t *list, int tag, const char *name)
1161 {
1162 	const dki_t	*curr;
1163 
1164 	curr = list;
1165 	if ( tag )
1166 		while ( curr && (tag != curr->tag ||
1167 				(name && *name && strcmp (name, curr->name) != 0)) )
1168 			curr = curr->next;
1169 	else if ( name && *name )
1170 		while ( curr && strcmp (name, curr->name) != 0 )
1171 			curr = curr->next;
1172 	else
1173 		curr = NULL;
1174 
1175 	return curr;
1176 }
1177 
1178 #if defined(USE_TREE) && USE_TREE
1179 /*****************************************************************
1180 **	dki_tadd ()	add a key to the given tree
1181 *****************************************************************/
1182 dki_t	*dki_tadd (dki_t **tree, dki_t *new, int sub_before)
1183 {
1184 	dki_t	**p;
1185 
1186 	if ( sub_before )
1187 		p = tsearch (new, tree, dki_namecmp);
1188 	else
1189 		p = tsearch (new, tree, dki_revnamecmp);
1190 	if ( *p == new )
1191 		dbg_val ("dki_tadd: New entry %s added\n", new->name);
1192 	else
1193 	{
1194 		dbg_val ("dki_tadd: New key added to %s\n", new->name);
1195 		dki_add (p, new);
1196 	}
1197 
1198 	return *p;
1199 }
1200 
1201 /*****************************************************************
1202 **	dki_tsearch ()	search a key with the given tag, or the first
1203 **			occurence of a key with the given name
1204 *****************************************************************/
1205 const dki_t	*dki_tsearch (const dki_t *tree, int tag, const char *name)
1206 {
1207 	dki_t	search;
1208 	dki_t	**p;
1209 
1210 	search.tag = tag;
1211 	snprintf (search.name, sizeof (search.name), "%s", name);
1212 	p = tfind (&search, &tree, dki_namecmp);
1213 	if ( p == NULL )
1214 		return NULL;
1215 
1216 	return dki_search (*p, tag, name);
1217 }
1218 #endif
1219 
1220 /*****************************************************************
1221 **	dki_find ()	find the n'th ksk or zsk key with given status
1222 *****************************************************************/
1223 const dki_t	*dki_find (const dki_t *list, int ksk, int status, int no)
1224 {
1225 	const	dki_t	*dkp;
1226 	const	dki_t	*last;
1227 
1228 	last = NULL;
1229 	for ( dkp = list; no > 0 && dkp; dkp = dkp->next )
1230 		if ( dki_isksk (dkp) == ksk && dki_status (dkp) == status )
1231 		{
1232 			no--;
1233 			last = dkp;
1234 		}
1235 
1236 	return last;
1237 }
1238 
1239 /*****************************************************************
1240 **	dki_findalgo ()	find the n'th ksk or zsk key with given
1241 **			algorithm and status
1242 *****************************************************************/
1243 const dki_t	*dki_findalgo (const dki_t *list, int ksk, int alg, int status, int no)
1244 {
1245 	const	dki_t	*dkp;
1246 	const	dki_t	*last;
1247 
1248 	last = NULL;
1249 	for ( dkp = list; no > 0 && dkp; dkp = dkp->next )
1250 		if ( dki_isksk (dkp) == ksk && dki_algo (dkp) == alg &&
1251 						dki_status (dkp) == status )
1252 		{
1253 			no--;
1254 			last = dkp;
1255 		}
1256 
1257 	return last;
1258 }
1259