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