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