1/* $NetBSD$ */ 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*****************************************************************/ 68static char dki_estr[255+1]; 69 70static 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 86static 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 163static 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 181static int dki_setstat (dki_t *dkp, int status, int preserve_time); 182 183/***************************************************************** 184** public function definition 185*****************************************************************/ 186 187/***************************************************************** 188** dki_free () 189*****************************************************************/ 190void 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*****************************************************************/ 202void 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*****************************************************************/ 224void 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#if defined(BIND_VERSION) && BIND_VERSION >= 970 233# define KEYGEN_COMPMODE "-C -q " /* this is the compability mode needed by BIND 9.7 */ 234#else 235# define KEYGEN_COMPMODE "" 236#endif 237/***************************************************************** 238** dki_new () 239** create new keyfile 240** allocate memory for new dki key and init with keyfile 241*****************************************************************/ 242dki_t *dki_new (const char *dir, const char *name, int ksk, int algo, int bitsize, const char *rfile, int lf_days) 243{ 244 char cmdline[511+1]; 245 char fname[254+1]; 246 char randfile[254+1]; 247 FILE *fp; 248 int len; 249 char *flag = ""; 250 char *expflag = ""; 251 dki_t *new; 252 253 if ( ksk ) 254 flag = "-f KSK"; 255 256 randfile[0] = '\0'; 257 if ( rfile && *rfile ) 258 snprintf (randfile, sizeof (randfile), "-r %.250s ", rfile); 259 260 if ( algo == DK_ALGO_RSA || algo == DK_ALGO_RSASHA1 || algo == DK_ALGO_RSASHA256 || algo == DK_ALGO_RSASHA512 ) 261 expflag = "-e "; 262 263 if ( dir && *dir ) 264 snprintf (cmdline, sizeof (cmdline), "cd %s ; %s %s%s%s-n ZONE -a %s -b %d %s %s", 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", 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 || fgets (fname, sizeof fname, fp) == NULL ) 273 return NULL; 274 pclose (fp); 275 276 len = strlen (fname) - 1; 277 if ( len >= 0 && fname[len] == '\n' ) 278 fname[len] = '\0'; 279 280 new = dki_read (dir, fname); 281 if ( new ) 282 dki_setlifetime (new, lf_days); /* sets gentime + proposed lifetime */ 283 284 return new; 285} 286 287/***************************************************************** 288** dki_read () 289** read key from file 'filename' (independed of the extension) 290*****************************************************************/ 291dki_t *dki_read (const char *dirname, const char *filename) 292{ 293 dki_t *dkp; 294 FILE *fp; 295 struct stat st; 296 int len; 297 int err; 298 char fname[MAX_FNAMESIZE+1]; 299 char path[MAX_PATHSIZE+1]; 300 301 dki_estr[0] = '\0'; 302 if ( (dkp = dki_alloc ()) == NULL ) 303 return (NULL); 304 305 len = sizeof (fname) - 1; 306 fname[len] = '\0'; 307 strncpy (fname, filename, len); 308 309 len = strlen (fname); /* delete extension */ 310 if ( len > 4 && strcmp (&fname[len - 4], DKI_KEY_FILEEXT) == 0 ) 311 fname[len - 4] = '\0'; 312 else if ( len > 10 && strcmp (&fname[len - 10], DKI_PUB_FILEEXT) == 0 ) 313 fname[len - 10] = '\0'; 314 else if ( len > 8 && strcmp (&fname[len - 8], DKI_ACT_FILEEXT) == 0 ) 315 fname[len - 8] = '\0'; 316 else if ( len > 12 && strcmp (&fname[len - 12], DKI_DEP_FILEEXT) == 0 ) 317 fname[len - 12] = '\0'; 318 dbg_line (); 319 320 assert (strlen (dirname)+1 < sizeof (dkp->dname)); 321 strcpy (dkp->dname, dirname); 322 323 assert (strlen (fname)+1 < sizeof (dkp->fname)); 324 strcpy (dkp->fname, fname); 325 dbg_line (); 326 if ( sscanf (fname, "K%254[^+]+%hd+%d", dkp->name, &dkp->algo, &dkp->tag) != 3 ) 327 { 328 snprintf (dki_estr, sizeof (dki_estr), 329 "dki_read: Filename don't match expected format (%s)", fname); 330 return (NULL); 331 } 332 333 pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_KEY_FILEEXT); 334 dbg_val ("dki_read: path \"%s\"\n", path); 335 if ( (fp = fopen (path, "r")) == NULL ) 336 { 337 snprintf (dki_estr, sizeof (dki_estr), 338 "dki_read: Can\'t open file \"%s\" for reading", path); 339 return (NULL); 340 } 341 342 dbg_line (); 343 if ( (err = dki_readfile (fp, dkp)) != 0 ) 344 { 345 dbg_line (); 346 snprintf (dki_estr, sizeof (dki_estr), 347 "dki_read: Can\'t read key from file %s (errno %d)", path, err); 348 fclose (fp); 349 return (NULL); 350 } 351 352 dbg_line (); 353 if ( fstat (fileno(fp), &st) ) 354 { 355 snprintf (dki_estr, sizeof (dki_estr), 356 "dki_read: Can\'t stat file %s", fname); 357 return (NULL); 358 } 359 dkp->time = st.st_mtime; 360 361 dbg_line (); 362 pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_ACT_FILEEXT); 363 if ( fileexist (path) ) 364 { 365 if ( dki_isrevoked (dkp) ) 366 dkp->status = DKI_REV; 367 else 368 dkp->status = DKI_ACT; 369 } 370 else 371 { 372 pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_PUB_FILEEXT); 373 if ( fileexist (path) ) 374 dkp->status = DKI_PUB; 375 else 376 { 377 pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_DEP_FILEEXT); 378 if ( fileexist (path) ) 379 dkp->status = DKI_DEP; 380 else 381 dkp->status = DKI_SEP; 382 } 383 } 384 385 dbg_line (); 386 fclose (fp); 387 388 dbg_line (); 389 return dkp; 390} 391 392/***************************************************************** 393** dki_readdir () 394** read key files from directory 'dir' and, if recursive is 395** true, from all directorys below that. 396*****************************************************************/ 397int dki_readdir (const char *dir, dki_t **listp, int recursive) 398{ 399 dki_t *dkp; 400 DIR *dirp; 401 struct dirent *dentp; 402 char path[MAX_PATHSIZE+1]; 403 404 dbg_val ("directory: opendir(%s)\n", dir); 405 if ( (dirp = opendir (dir)) == NULL ) 406 return 0; 407 408 while ( (dentp = readdir (dirp)) != NULL ) 409 { 410 if ( is_dotfilename (dentp->d_name) ) 411 continue; 412 413 dbg_val ("directory: check %s\n", dentp->d_name); 414 pathname (path, sizeof (path), dir, dentp->d_name, NULL); 415 if ( is_directory (path) && recursive ) 416 { 417 dbg_val ("directory: recursive %s\n", path); 418 dki_readdir (path, listp, recursive); 419 } 420 else if ( is_keyfilename (dentp->d_name) ) 421 if ( (dkp = dki_read (dir, dentp->d_name)) ) 422 dki_add (listp, dkp); 423 } 424 closedir (dirp); 425 return 1; 426} 427 428/***************************************************************** 429** dki_setstatus_preservetime () 430** set status of key and change extension to 431** ".published", ".private" or ".depreciated" 432*****************************************************************/ 433int dki_setstatus_preservetime (dki_t *dkp, int status) 434{ 435 return dki_setstat (dkp, status, 1); 436} 437 438/***************************************************************** 439** dki_setstatus () 440** set status of key and change extension to 441** ".published", ".private" or ".depreciated" 442*****************************************************************/ 443int dki_setstatus (dki_t *dkp, int status) 444{ 445 return dki_setstat (dkp, status, 0); 446} 447 448/***************************************************************** 449** dki_setstat () 450** low level function of dki_setstatus and dki_setstatus_preservetime 451*****************************************************************/ 452static int dki_setstat (dki_t *dkp, int status, int preserve_time) 453{ 454 char frompath[MAX_PATHSIZE+1]; 455 char topath[MAX_PATHSIZE+1]; 456 time_t totime; 457 time_t currtime; 458 459 if ( dkp == NULL ) 460 return 0; 461 462 currtime = time (NULL); 463 status = tolower (status); 464 switch ( dkp->status ) /* look at old status */ 465 { 466 case 'r': 467 if ( status == 'r' ) 468 return 1; 469 break; 470 case 'a': 471 if ( status == 'a' ) 472 return 1; 473 pathname (frompath, sizeof (frompath), dkp->dname, dkp->fname, DKI_ACT_FILEEXT); 474 break; 475 case 'd': 476 if ( status == 'd' ) 477 return 1; 478 pathname (frompath, sizeof (frompath), dkp->dname, dkp->fname, DKI_DEP_FILEEXT); 479 break; 480 case 'p': /* or 's' */ 481 if ( status == 'p' || status == 's' ) 482 return 1; 483 pathname (frompath, sizeof (frompath), dkp->dname, dkp->fname, DKI_PUB_FILEEXT); 484 break; 485 default: 486 /* TODO: set error code */ 487 return 0; 488 } 489 490 dbg_val ("dki_setstat: \"%s\"\n", frompath); 491 dbg_val ("dki_setstat: to status \"%c\"\n", status); 492 493 /* a state change could result in different things: */ 494 /* 1) write a new keyfile when the REVOKE bit is set or unset */ 495 if ( status == 'r' || (status == 'a' && dki_isrevoked (dkp)) ) 496 { 497 pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_KEY_FILEEXT); 498 499 if ( status == 'r' ) 500 dki_setflag (dkp, DK_FLAG_REVOKE); /* set REVOKE bit */ 501 else 502 dki_unsetflag (dkp, DK_FLAG_REVOKE); /* clear REVOKE bit */ 503 504 505 dki_writeinfo (dkp, topath); /* ..and write it to the key file */ 506 507 if ( !preserve_time ) 508 touch (topath, time (NULL)); 509 510 return 0; 511 } 512 513 514 /* 2) change the filename of the private key in all other cases */ 515 totime = 0L; 516 if ( preserve_time ) 517 totime = file_mtime (frompath); /* get original timestamp */ 518 topath[0] = '\0'; 519 switch ( status ) 520 { 521 case 'a': 522 pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_ACT_FILEEXT); 523 break; 524 case 'd': 525 pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_DEP_FILEEXT); 526 break; 527 case 's': /* standby means a "published KSK" */ 528 if ( !dki_isksk (dkp) ) 529 return 2; 530 status = 'p'; 531 /* fall through */ 532 case 'p': 533 pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_PUB_FILEEXT); 534 break; 535 } 536 537 if ( topath[0] ) 538 { 539 dbg_val ("dki_setstat: to \"%s\"\n", topath); 540 if ( link (frompath, topath) == 0 ) 541 unlink (frompath); 542 dkp->status = status; 543 if ( !totime ) 544 totime = time (NULL); /* set .key file to current time */ 545 pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_KEY_FILEEXT); 546 touch (topath, totime); /* store/restore time of status change */ 547 } 548 549 return 0; 550} 551 552/***************************************************************** 553** dki_remove () 554** rename files associated with key, so that the keys are not 555** recognized by the zkt tools e.g. 556** Kdo.ma.in.+001+12345.key ==> kdo.ma.in.+001+12345.key 557** (second one starts with a lower case 'k') 558*****************************************************************/ 559dki_t *dki_remove (dki_t *dkp) 560{ 561 char path[MAX_PATHSIZE+1]; 562 char newpath[MAX_PATHSIZE+1]; 563 char newfile[MAX_FNAMESIZE+1]; 564 dki_t *next; 565 const char **pext; 566 static const char *ext[] = { 567 DKI_KEY_FILEEXT, DKI_PUB_FILEEXT, 568 DKI_ACT_FILEEXT, DKI_DEP_FILEEXT, 569 NULL 570 }; 571 572 if ( dkp == NULL ) 573 return NULL; 574 575 strncpy (newfile, dkp->fname, sizeof (newfile)); 576 *newfile = tolower (*newfile); 577 for ( pext = ext; *pext; pext++ ) 578 { 579 pathname (path, sizeof (path), dkp->dname, dkp->fname, *pext); 580 if ( fileexist (path) ) 581 { 582 pathname (newpath, sizeof (newpath), dkp->dname, newfile, *pext); 583 584 dbg_val2 ("dki_remove: %s ==> %s \n", path, newpath); 585 rename (path, newpath); 586 } 587 } 588 next = dkp->next; 589 dki_free (dkp); 590 591 return next; 592} 593 594/***************************************************************** 595** dki_destroy () 596** delete files associated with key and free allocated memory 597*****************************************************************/ 598dki_t *dki_destroy (dki_t *dkp) 599{ 600 char path[MAX_PATHSIZE+1]; 601 dki_t *next; 602 const char **pext; 603 static const char *ext[] = { 604 DKI_KEY_FILEEXT, DKI_PUB_FILEEXT, 605 DKI_ACT_FILEEXT, DKI_DEP_FILEEXT, 606 NULL 607 }; 608 609 if ( dkp == NULL ) 610 return NULL; 611 612 for ( pext = ext; *pext; pext++ ) 613 { 614 pathname (path, sizeof (path), dkp->dname, dkp->fname, *pext); 615 if ( fileexist (path) ) 616 { 617 dbg_val ("dki_remove: %s \n", path); 618 unlink (path); 619 } 620 } 621 next = dkp->next; 622 dki_free (dkp); 623 624 return next; 625} 626 627/***************************************************************** 628** dki_algo2str () 629** return a string describing the key algorithm 630*****************************************************************/ 631char *dki_algo2str (int algo) 632{ 633 switch ( algo ) 634 { 635 case DK_ALGO_RSA: return ("RSAMD5"); 636 case DK_ALGO_DH: return ("DH"); 637 case DK_ALGO_DSA: return ("DSA"); 638 case DK_ALGO_EC: return ("EC"); 639 case DK_ALGO_RSASHA1: return ("RSASHA1"); 640 case DK_ALGO_NSEC3DSA: return ("NSEC3DSA"); 641 case DK_ALGO_NSEC3RSASHA1: return ("NSEC3RSASHA1"); 642 case DK_ALGO_RSASHA256: return ("RSASHA256"); 643 case DK_ALGO_RSASHA512: return ("RSASHA512"); 644 } 645 return ("unknown"); 646} 647 648/***************************************************************** 649** dki_algo2sstr () 650** return a short string describing the key algorithm 651*****************************************************************/ 652char *dki_algo2sstr (int algo) 653{ 654 switch ( algo ) 655 { 656 case DK_ALGO_RSA: return ("RSAMD5"); 657 case DK_ALGO_DH: return ("DH"); 658 case DK_ALGO_DSA: return ("DSA"); 659 case DK_ALGO_EC: return ("EC"); 660 case DK_ALGO_RSASHA1: return ("RSASHA1"); 661 case DK_ALGO_NSEC3DSA: return ("N3DSA"); 662 case DK_ALGO_NSEC3RSASHA1: return ("N3RSA1"); 663 case DK_ALGO_RSASHA256: return ("RSASHA2"); 664 case DK_ALGO_RSASHA512: return ("RSASHA5"); 665 } 666 return ("unknown"); 667} 668 669/***************************************************************** 670** dki_geterrstr () 671** return error string 672*****************************************************************/ 673const char *dki_geterrstr () 674{ 675 return dki_estr; 676} 677 678/***************************************************************** 679** dki_prt_dnskey () 680*****************************************************************/ 681int dki_prt_dnskey (const dki_t *dkp, FILE *fp) 682{ 683 return dki_prt_dnskeyttl (dkp, fp, 0); 684} 685 686/***************************************************************** 687** dki_prt_dnskeyttl () 688*****************************************************************/ 689int dki_prt_dnskeyttl (const dki_t *dkp, FILE *fp, int ttl) 690{ 691 char *p; 692 693 if ( dkp == NULL ) 694 return 0; 695 696 fprintf (fp, "%s ", dkp->name); 697 if ( ttl > 0 ) 698 fprintf (fp, "%d ", ttl); 699 fprintf (fp, "IN DNSKEY "); 700 fprintf (fp, "%d 3 %d (", dkp->flags, dkp->algo); 701 fprintf (fp, "\n\t\t\t"); 702 for ( p = dkp->pubkey; *p ; p++ ) 703 if ( *p == ' ' ) 704 fprintf (fp, "\n\t\t\t"); 705 else 706 putc (*p, fp); 707 fprintf (fp, "\n\t\t"); 708 if ( dki_isrevoked (dkp) ) 709 fprintf (fp, ") ; key id = %u (original key id = %u)", (dkp->tag + 128) % 65535, dkp->tag); 710 else 711 fprintf (fp, ") ; key id = %u", dkp->tag); 712 fprintf (fp, "\n"); 713 714 return 1; 715} 716 717/***************************************************************** 718** dki_prt_dnskey_raw () 719*****************************************************************/ 720int dki_prt_dnskey_raw (const dki_t *dkp, FILE *fp) 721{ 722 int days; 723 724 if ( dkp == NULL ) 725 return 0; 726 727 if ( dkp->gentime ) 728 fprintf (fp, ";%%\tgenerationtime=%s\n", time2isostr (dkp->gentime, 's')); 729 if ( (days = dki_lifetimedays (dkp)) ) 730 fprintf (fp, ";%%\tlifetime=%dd\n", days); 731 if ( dkp->exptime ) 732 fprintf (fp, ";%%\texpirationtime=%s\n", time2isostr (dkp->exptime, 's')); 733 734 fprintf (fp, "%s ", dkp->name); 735#if 0 736 if ( ttl > 0 ) 737 fprintf (fp, "%d ", ttl); 738#endif 739 fprintf (fp, "IN DNSKEY "); 740 fprintf (fp, "%d 3 %d ", dkp->flags, dkp->algo); 741 fprintf (fp, "%s\n", dkp->pubkey); 742 743 return 1; 744} 745 746/***************************************************************** 747** dki_prt_comment () 748*****************************************************************/ 749int dki_prt_comment (const dki_t *dkp, FILE *fp) 750{ 751 int len = 0; 752 753 if ( dkp == NULL ) 754 return len; 755 len += fprintf (fp, "; %s ", dkp->name); 756 len += fprintf (fp, "tag=%u ", dkp->tag); 757 len += fprintf (fp, "algo=%s ", dki_algo2str(dkp->algo)); 758 len += fprintf (fp, "generated %s\n", time2str (dkp->time, 's')); 759 760 return len; 761} 762 763/***************************************************************** 764** dki_prt_trustedkey () 765*****************************************************************/ 766int dki_prt_trustedkey (const dki_t *dkp, FILE *fp) 767{ 768 char *p; 769 int spaces; 770 int len = 0; 771 772 if ( dkp == NULL ) 773 return len; 774 len += fprintf (fp, "\"%s\" ", dkp->name); 775 spaces = 22 - (strlen (dkp->name) + 3); 776 len += fprintf (fp, "%*s", spaces > 0 ? spaces : 0 , " "); 777 len += fprintf (fp, "%d 3 %d ", dkp->flags, dkp->algo); 778 if ( spaces < 0 ) 779 len += fprintf (fp, "\n\t\t\t%7s", " "); 780 len += fprintf (fp, "\""); 781 for ( p = dkp->pubkey; *p ; p++ ) 782 if ( *p == ' ' ) 783 len += fprintf (fp, "\n\t\t\t\t"); 784 else 785 putc (*p, fp), len += 1; 786 787 if ( dki_isrevoked (dkp) ) 788 len += fprintf (fp, "\" ; # key id = %u (original key id = %u)\n\n", (dkp->tag + 128) % 65535, dkp->tag); 789 else 790 len += fprintf (fp, "\" ; # key id = %u\n\n", dkp->tag); 791 return len; 792} 793 794 795/***************************************************************** 796** dki_cmp () return <0 | 0 | >0 797*****************************************************************/ 798int dki_cmp (const dki_t *a, const dki_t *b) 799{ 800 int res; 801 802 if ( a == NULL ) return -1; 803 if ( b == NULL ) return 1; 804 805 /* sort by domain name, */ 806 if ( (res = domaincmp (a->name, b->name)) != 0 ) 807 return res; 808 809 /* then by key type, */ 810 if ( (res = dki_isksk (b) - dki_isksk (a)) != 0 ) 811 return res; 812 813 /* and last by creation time, */ 814 return (ulong)a->time - (ulong)b->time; 815} 816 817#if defined(USE_TREE) && USE_TREE 818/***************************************************************** 819** dki_allcmp () return <0 | 0 | >0 820*****************************************************************/ 821int dki_allcmp (const dki_t *a, const dki_t *b) 822{ 823 int res; 824 825 if ( a == NULL ) return -1; 826 if ( b == NULL ) return 1; 827 828// fprintf (stderr, "dki_allcmp %s, %s)\n", a->name, b->name); 829 /* sort by domain name, */ 830 if ( (res = domaincmp (a->name, b->name)) != 0 ) 831 return res; 832 833 /* then by key type, */ 834 if ( (res = dki_isksk (b) - dki_isksk (a)) != 0 ) 835 return res; 836 837 /* creation time, */ 838 if ( (res = (ulong)a->time - (ulong)b->time) != 0 ) 839 return res; 840 841 /* and last by tag */ 842 return a->tag - b->tag; 843} 844 845/***************************************************************** 846** dki_namecmp () return <0 | 0 | >0 847*****************************************************************/ 848int dki_namecmp (const dki_t *a, const dki_t *b) 849{ 850 if ( a == NULL ) return -1; 851 if ( b == NULL ) return 1; 852 853 return domaincmp (a->name, b->name); 854} 855 856/***************************************************************** 857** dki_revnamecmp () return <0 | 0 | >0 858*****************************************************************/ 859int dki_revnamecmp (const dki_t *a, const dki_t *b) 860{ 861 if ( a == NULL ) return -1; 862 if ( b == NULL ) return 1; 863 864 return domaincmp_dir (a->name, b->name, 0); 865} 866 867/***************************************************************** 868** dki_tagcmp () return <0 | 0 | >0 869*****************************************************************/ 870int dki_tagcmp (const dki_t *a, const dki_t *b) 871{ 872 if ( a == NULL ) return -1; 873 if ( b == NULL ) return 1; 874 875 return a->tag - b->tag; 876} 877#endif 878 879/***************************************************************** 880** dki_timecmp () 881*****************************************************************/ 882int dki_timecmp (const dki_t *a, const dki_t *b) 883{ 884 if ( a == NULL ) return -1; 885 if ( b == NULL ) return 1; 886 887 return ((ulong)a->time - (ulong)b->time); 888} 889 890/***************************************************************** 891** dki_algo () return the algorithm of the key 892*****************************************************************/ 893time_t dki_algo (const dki_t *dkp) 894{ 895 assert (dkp != NULL); 896 return (dkp->algo); 897} 898 899/***************************************************************** 900** dki_time () return the timestamp of the key 901*****************************************************************/ 902time_t dki_time (const dki_t *dkp) 903{ 904 assert (dkp != NULL); 905 return (dkp->time); 906} 907 908/***************************************************************** 909** dki_exptime () return the expiration timestamp of the key 910*****************************************************************/ 911time_t dki_exptime (const dki_t *dkp) 912{ 913 assert (dkp != NULL); 914 return (dkp->exptime); 915} 916 917/***************************************************************** 918** dki_lifetime (dkp) return the lifetime of the key in sec! 919*****************************************************************/ 920time_t dki_lifetime (const dki_t *dkp) 921{ 922 assert (dkp != NULL); 923 return (dkp->lifetime); 924} 925 926/***************************************************************** 927** dki_lifetimedays (dkp) return the lifetime of the key in days! 928*****************************************************************/ 929ushort dki_lifetimedays (const dki_t *dkp) 930{ 931 assert (dkp != NULL); 932 return (dkp->lifetime / DAYSEC); 933} 934 935/***************************************************************** 936** dki_gentime (dkp) return the generation timestamp of the key 937*****************************************************************/ 938time_t dki_gentime (const dki_t *dkp) 939{ 940 assert (dkp != NULL); 941 return (dkp->gentime > 0L ? dkp->gentime: dkp->time); 942} 943 944/***************************************************************** 945** dki_setlifetime (dkp, int days) 946** set the lifetime in days (and also the gentime if not set) 947** return the old lifetime of the key in days! 948*****************************************************************/ 949ushort dki_setlifetime (dki_t *dkp, int days) 950{ 951 ulong lifetsec; 952 char path[MAX_PATHSIZE+1]; 953 954 assert (dkp != NULL); 955 956 lifetsec = dkp->lifetime; /* old lifetime */ 957 dkp->lifetime = days * DAYSEC; /* set new lifetime */ 958 959 dbg_val1 ("dki_setlifetime (%d)\n", days); 960 if ( lifetsec == 0 ) /* initial setup (old lifetime was zero)? */ 961 dkp->gentime = dkp->time; 962 963 pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_KEY_FILEEXT); 964 dki_writeinfo (dkp, path); 965 966 return (lifetsec / DAYSEC); 967} 968 969/***************************************************************** 970** dki_setexptime (dkp, time_t sec) 971** set the expiration time of the key in seconds since the epoch 972** return the old exptime 973*****************************************************************/ 974time_t dki_setexptime (dki_t *dkp, time_t sec) 975{ 976 char path[MAX_PATHSIZE+1]; 977 time_t oldexptime; 978 979 assert (dkp != NULL); 980 981 dbg_val1 ("dki_setexptime (%ld)\n", sec); 982 oldexptime = dkp->exptime; 983 dkp->exptime = sec; 984 985 pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_KEY_FILEEXT); 986 dki_writeinfo (dkp, path); 987 988#if 0 /* not necessary ? */ 989 touch (path, time (NULL)); 990#endif 991 return (oldexptime); 992} 993 994/***************************************************************** 995** dki_age () return age of key in seconds since 'curr' 996*****************************************************************/ 997int dki_age (const dki_t *dkp, time_t curr) 998{ 999 assert (dkp != NULL); 1000 return ((ulong)curr - (ulong)dkp->time); 1001} 1002 1003/***************************************************************** 1004** dki_getflag () return the flags field of a key 1005*****************************************************************/ 1006dk_flag_t dki_getflag (const dki_t *dkp, time_t curr) 1007{ 1008 return dkp->flags; 1009} 1010 1011/***************************************************************** 1012** dki_setflag () set a flag of a key 1013*****************************************************************/ 1014dk_flag_t dki_setflag (dki_t *dkp, dk_flag_t flag) 1015{ 1016 return dkp->flags |= (ushort)flag; 1017} 1018 1019/***************************************************************** 1020** dki_unsetflag () unset a flag of a key 1021*****************************************************************/ 1022dk_flag_t dki_unsetflag (dki_t *dkp, dk_flag_t flag) 1023{ 1024 return dkp->flags &= ~((ushort)flag); 1025} 1026 1027/***************************************************************** 1028** dki_isksk () 1029*****************************************************************/ 1030int dki_isksk (const dki_t *dkp) 1031{ 1032 assert (dkp != NULL); 1033 return (dkp->flags & DK_FLAG_KSK) == DK_FLAG_KSK; 1034} 1035 1036/***************************************************************** 1037** dki_isrevoked () 1038*****************************************************************/ 1039int dki_isrevoked (const dki_t *dkp) 1040{ 1041 assert (dkp != NULL); 1042 return (dkp->flags & DK_FLAG_REVOKE) == DK_FLAG_REVOKE; 1043} 1044 1045/***************************************************************** 1046** dki_isdepreciated () 1047*****************************************************************/ 1048int dki_isdepreciated (const dki_t *dkp) 1049{ 1050 return dki_status (dkp) == DKI_DEPRECIATED; 1051} 1052 1053/***************************************************************** 1054** dki_isactive () 1055*****************************************************************/ 1056int dki_isactive (const dki_t *dkp) 1057{ 1058 return dki_status (dkp) == DKI_ACTIVE; 1059} 1060 1061/***************************************************************** 1062** dki_ispublished () 1063*****************************************************************/ 1064int dki_ispublished (const dki_t *dkp) 1065{ 1066 return dki_status (dkp) == DKI_PUBLISHED; 1067} 1068 1069 1070/***************************************************************** 1071** dki_status () return key status 1072*****************************************************************/ 1073dk_status_t dki_status (const dki_t *dkp) 1074{ 1075 assert (dkp != NULL); 1076 return (dkp->status); 1077} 1078 1079/***************************************************************** 1080** dki_statusstr () return key status as string 1081*****************************************************************/ 1082const char *dki_statusstr (const dki_t *dkp) 1083{ 1084 assert (dkp != NULL); 1085 switch ( dkp->status ) 1086 { 1087 case DKI_ACT: return "active"; 1088 case DKI_PUB: if ( dki_isksk (dkp) ) 1089 return "standby"; 1090 else 1091 return "published"; 1092 case DKI_DEP: return "depreciated"; 1093 case DKI_REV: return "revoked"; 1094 case DKI_SEP: return "sep"; 1095 } 1096 return "unknown"; 1097} 1098 1099/***************************************************************** 1100** dki_add () add a key to the given list 1101*****************************************************************/ 1102dki_t *dki_add (dki_t **list, dki_t *new) 1103{ 1104 dki_t *curr; 1105 dki_t *last; 1106 1107 if ( list == NULL ) 1108 return NULL; 1109 if ( new == NULL ) 1110 return *list; 1111 1112 last = curr = *list; 1113 while ( curr && dki_cmp (curr, new) < 0 ) 1114 { 1115 last = curr; 1116 curr = curr->next; 1117 } 1118 1119 if ( curr == *list ) /* add node at start of list */ 1120 *list = new; 1121 else /* add node at end or between two nodes */ 1122 last->next = new; 1123 new->next = curr; 1124 1125 return *list; 1126} 1127 1128/***************************************************************** 1129** dki_search () search a key with the given tag, or the first 1130** occurence of a key with the given name 1131*****************************************************************/ 1132const dki_t *dki_search (const dki_t *list, int tag, const char *name) 1133{ 1134 const dki_t *curr; 1135 1136 curr = list; 1137 if ( tag ) 1138 while ( curr && (tag != curr->tag || 1139 (name && *name && strcmp (name, curr->name) != 0)) ) 1140 curr = curr->next; 1141 else if ( name && *name ) 1142 while ( curr && strcmp (name, curr->name) != 0 ) 1143 curr = curr->next; 1144 else 1145 curr = NULL; 1146 1147 return curr; 1148} 1149 1150#if defined(USE_TREE) && USE_TREE 1151/***************************************************************** 1152** dki_tadd () add a key to the given tree 1153*****************************************************************/ 1154dki_t *dki_tadd (dki_t **tree, dki_t *new, int sub_before) 1155{ 1156 dki_t **p; 1157 1158 if ( sub_before ) 1159 p = tsearch (new, tree, dki_namecmp); 1160 else 1161 p = tsearch (new, tree, dki_revnamecmp); 1162 if ( *p == new ) 1163 dbg_val ("dki_tadd: New entry %s added\n", new->name); 1164 else 1165 { 1166 dbg_val ("dki_tadd: New key added to %s\n", new->name); 1167 dki_add (p, new); 1168 } 1169 1170 return *p; 1171} 1172 1173/***************************************************************** 1174** dki_tsearch () search a key with the given tag, or the first 1175** occurence of a key with the given name 1176*****************************************************************/ 1177const dki_t *dki_tsearch (const dki_t *tree, int tag, const char *name) 1178{ 1179 dki_t search; 1180 dki_t **p; 1181 1182 search.tag = tag; 1183 snprintf (search.name, sizeof (search.name), "%s", name); 1184 p = tfind (&search, &tree, dki_namecmp); 1185 if ( p == NULL ) 1186 return NULL; 1187 1188 return dki_search (*p, tag, name); 1189} 1190#endif 1191 1192/***************************************************************** 1193** dki_find () find the n'th ksk or zsk key with given status 1194*****************************************************************/ 1195const dki_t *dki_find (const dki_t *list, int ksk, int status, int no) 1196{ 1197 const dki_t *dkp; 1198 const dki_t *last; 1199 1200 last = NULL; 1201 for ( dkp = list; no > 0 && dkp; dkp = dkp->next ) 1202 if ( dki_isksk (dkp) == ksk && dki_status (dkp) == status ) 1203 { 1204 no--; 1205 last = dkp; 1206 } 1207 1208 return last; 1209} 1210 1211/***************************************************************** 1212** dki_findalgo () find the n'th ksk or zsk key with given 1213** algorithm and status 1214*****************************************************************/ 1215const dki_t *dki_findalgo (const dki_t *list, int ksk, int alg, int status, int no) 1216{ 1217 const dki_t *dkp; 1218 const dki_t *last; 1219 1220 last = NULL; 1221 for ( dkp = list; no > 0 && dkp; dkp = dkp->next ) 1222 if ( dki_isksk (dkp) == ksk && dki_algo (dkp) == alg && 1223 dki_status (dkp) == status ) 1224 { 1225 no--; 1226 last = dkp; 1227 } 1228 1229 return last; 1230} 1231