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