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
dki_alloc()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
dki_readfile(FILE * fp,dki_t * dkp)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
dki_writeinfo(const dki_t * dkp,const char * path)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 *****************************************************************/
dki_free(dki_t * dkp)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 *****************************************************************/
dki_freelist(dki_t ** listp)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 *****************************************************************/
dki_tfree(dki_t ** tree)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 *****************************************************************/
dki_new(const char * dir,const char * name,int ksk,int algo,int bitsize,const char * rfile,int lf_days)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 *****************************************************************/
dki_read(const char * dirname,const char * filename)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 *****************************************************************/
dki_readdir(const char * dir,dki_t ** listp,int recursive)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 *****************************************************************/
dki_setstatus_preservetime(dki_t * dkp,int status)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 *****************************************************************/
dki_setstatus(dki_t * dkp,int status)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 *****************************************************************/
dki_setstat(dki_t * dkp,int status,int preserve_time)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 *****************************************************************/
dki_remove(dki_t * dkp)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 *****************************************************************/
dki_destroy(dki_t * dkp)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 *****************************************************************/
dki_algo2str(int algo)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 *****************************************************************/
dki_algo2sstr(int algo)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 *****************************************************************/
dki_geterrstr()668 const char *dki_geterrstr ()
669 {
670 return dki_estr;
671 }
672
673 /*****************************************************************
674 ** dki_prt_dnskey ()
675 *****************************************************************/
dki_prt_dnskey(const dki_t * dkp,FILE * fp)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 *****************************************************************/
dki_prt_dnskeyttl(const dki_t * dkp,FILE * fp,int ttl)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 *****************************************************************/
dki_prt_dnskey_raw(const dki_t * dkp,FILE * fp)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 *****************************************************************/
dki_prt_comment(const dki_t * dkp,FILE * fp)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 *****************************************************************/
dki_prt_trustedkey(const dki_t * dkp,FILE * fp)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 *****************************************************************/
dki_prt_managedkey(const dki_t * dkp,FILE * fp)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 *****************************************************************/
dki_cmp(const dki_t * a,const dki_t * b)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 *****************************************************************/
dki_allcmp(const dki_t * a,const dki_t * b)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 *****************************************************************/
dki_namecmp(const dki_t * a,const dki_t * b)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 *****************************************************************/
dki_revnamecmp(const dki_t * a,const dki_t * b)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 *****************************************************************/
dki_tagcmp(const dki_t * a,const dki_t * b)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 *****************************************************************/
dki_timecmp(const dki_t * a,const dki_t * b)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 *****************************************************************/
dki_algo(const dki_t * dkp)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 *****************************************************************/
dki_time(const dki_t * dkp)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 *****************************************************************/
dki_exptime(const dki_t * dkp)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 *****************************************************************/
dki_lifetime(const dki_t * dkp)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 *****************************************************************/
dki_lifetimedays(const dki_t * dkp)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 *****************************************************************/
dki_gentime(const dki_t * dkp)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 *****************************************************************/
dki_setlifetime(dki_t * dkp,int days)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 *****************************************************************/
dki_setexptime(dki_t * dkp,time_t sec)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 *****************************************************************/
dki_age(const dki_t * dkp,time_t curr)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 *****************************************************************/
dki_getflag(const dki_t * dkp,time_t curr)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 *****************************************************************/
dki_setflag(dki_t * dkp,dk_flag_t flag)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 *****************************************************************/
dki_unsetflag(dki_t * dkp,dk_flag_t flag)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 *****************************************************************/
dki_isksk(const dki_t * dkp)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 *****************************************************************/
dki_isrevoked(const dki_t * dkp)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 *****************************************************************/
dki_isdepreciated(const dki_t * dkp)1076 int dki_isdepreciated (const dki_t *dkp)
1077 {
1078 return dki_status (dkp) == DKI_DEPRECIATED;
1079 }
1080
1081 /*****************************************************************
1082 ** dki_isactive ()
1083 *****************************************************************/
dki_isactive(const dki_t * dkp)1084 int dki_isactive (const dki_t *dkp)
1085 {
1086 return dki_status (dkp) == DKI_ACTIVE;
1087 }
1088
1089 /*****************************************************************
1090 ** dki_ispublished ()
1091 *****************************************************************/
dki_ispublished(const dki_t * dkp)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 *****************************************************************/
dki_status(const dki_t * dkp)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 *****************************************************************/
dki_statusstr(const dki_t * dkp)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 *****************************************************************/
dki_add(dki_t ** list,dki_t * new)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 *****************************************************************/
dki_search(const dki_t * list,int tag,const char * name)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 *****************************************************************/
dki_tadd(dki_t ** tree,dki_t * new,int sub_before)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 *****************************************************************/
dki_tsearch(const dki_t * tree,int tag,const char * name)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 *****************************************************************/
dki_find(const dki_t * list,int ksk,int status,int no)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 *****************************************************************/
dki_findalgo(const dki_t * list,int ksk,int alg,int status,int no)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