|
|
1.1.1.2 ! root 1: /* keymaint.c - Keyring maintenance pass routines for PGP. ! 2: PGP: Pretty Good(tm) Privacy - public key cryptography for the masses. ! 3: ! 4: (c) Copyright 1990-1992 by Philip Zimmermann. All rights reserved. ! 5: The author assumes no liability for damages resulting from the use ! 6: of this software, even if the damage results from defects in this ! 7: software. No warranty is expressed or implied. ! 8: ! 9: All the source code Philip Zimmermann wrote for PGP is available for ! 10: free under the "Copyleft" General Public License from the Free ! 11: Software Foundation. A copy of that license agreement is included in ! 12: the source release package of PGP. Code developed by others for PGP ! 13: is also freely available. Other code that has been incorporated into ! 14: PGP from other sources was either originally published in the public ! 15: domain or was used with permission from the various authors. See the ! 16: PGP User's Guide for more complete information about licensing, ! 17: patent restrictions on certain algorithms, trademarks, copyrights, ! 18: and export controls. ! 19: ! 20: keymaint.c implemented by Branko Lankester. ! 21: */ ! 22: ! 23: #include <stdio.h> ! 24: #include <time.h> ! 25: #include "mpilib.h" ! 26: #include "random.h" ! 27: #include "crypto.h" ! 28: #include "fileio.h" ! 29: #include "keymgmt.h" ! 30: #include "mpiio.h" ! 31: #include "language.h" ! 32: #include "pgp.h" ! 33: ! 34: ! 35: void setup_trust(); ! 36: int maint_pass1(FILE *f); ! 37: int maint_trace_chain(FILE *f); ! 38: int maint_cmpfiles(FILE *f, FILE *g); ! 39: int trace_sig_chain(FILE *f, byte *fromID, int owner_trust, int depth); ! 40: int check_secretkey(FILE *f, long keypos); ! 41: int set_legit(FILE *f, long trustpos, int trust_count); ! 42: long lookup_by_keyID(FILE *f, byte *srch_keyID); ! 43: void show_userid(FILE *f, byte *keyID); ! 44: int show_trust(byte, byte); ! 45: int show_legit(byte, byte); ! 46: void write_trust_pos(FILE *f, byte keyctrl, long pos); ! 47: ! 48: /* returned when trying to do a maintenance pass on a secret keyring or keyfile */ ! 49: #define ERR_NOTRUST -7 ! 50: ! 51: #define TRUST_MASK 7 /* mask for userid/signature trust bytes */ ! 52: #define SET_TRUST(b,v) (*(b) = (*(b) & ~TRUST_MASK) | (v)) ! 53: #define TRUST_LEV(b) ((b) & TRUST_MASK) ! 54: ! 55: #define TRUST_FAC(x) (trust_tbl[TRUST_LEV(x)]) ! 56: ! 57: /* ! 58: * table for tuning user paranoia index. ! 59: * values represent contribution of one signature indexed by the ! 60: * SIGTRUST of a signature ! 61: */ ! 62: int trust_tbl[8]; ! 63: ! 64: static int marginal_min; ! 65: static int complete_min; /* total count needed for a fully legit key */ ! 66: ! 67: int marg_min = 2; /* number of marginally trusted signatures needed for ! 68: a fully legit key (can be set in config.pgp). */ ! 69: int compl_min = 1; /* number of fully trusted signatures needed */ ! 70: ! 71: char trust_lst[8][16] = { ! 72: "undefined", /* PSTR("undefined") */ ! 73: "unknown", /* PSTR("unknown") */ ! 74: "untrusted", /* PSTR("untrusted") */ ! 75: "<3>", /* unused */ ! 76: "<4>", /* unused */ ! 77: "marginal", /* PSTR("marginal") */ ! 78: "complete", /* PSTR("complete") */ ! 79: "ultimate", /* PSTR("ultimate") */ ! 80: }; ! 81: ! 82: char legit_lst[4][16] = { ! 83: "undefined", ! 84: "untrusted", ! 85: "marginal", ! 86: "complete" ! 87: }; ! 88: ! 89: int trustlst_len = 9; /* length of longest trust word */ ! 90: int legitlst_len = 9; /* length of longest legit word */ ! 91: ! 92: char floppyring[MAX_PATH] = ""; ! 93: int max_cert_depth = 4; /* maximum nesting of signatures */ ! 94: ! 95: static boolean check_only = FALSE; ! 96: static boolean mverbose; ! 97: static FILE *sec_fp; ! 98: static FILE *floppy_fp = NULL; ! 99: static int undefined_trust; /* number of legit keys with undef. trust */ ! 100: ! 101: /* ! 102: * do a maintenance pass on keyring "ringfile" ! 103: * options can be: ! 104: * MAINT_CHECK check keyring only, "ringfile" will not be changed ! 105: * MAINT_SILENT used for implicit maintenance pass, does not print keyring contents ! 106: * MAINT_VERBOSE verbose output, shows signature chains ! 107: */ ! 108: int ! 109: maintenance(char *ringfile, int options) ! 110: { ! 111: FILE *f, *g; ! 112: int status; ! 113: char *tmpring; ! 114: char secretkeyring[MAX_PATH]; ! 115: extern boolean moreflag; ! 116: ! 117: check_only = (options & MAINT_CHECK) != 0; ! 118: mverbose = (options & MAINT_VERBOSE) != 0; ! 119: undefined_trust = 0; ! 120: if (max_cert_depth > 8) ! 121: max_cert_depth = 8; ! 122: ! 123: if ((tmpring = tempfile(TMP_TMPDIR)) == NULL) ! 124: return(-1); ! 125: if ((g = fopen(tmpring, FOPWPBIN)) == NULL) ! 126: return(-1); ! 127: ! 128: if ((f = fopen(ringfile,FOPRBIN)) == NULL) ! 129: { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile); ! 130: fclose(g); ! 131: return(-1); ! 132: } ! 133: ! 134: buildfilename(secretkeyring, SECRET_KEYRING_FILENAME); ! 135: if ((sec_fp = fopen(secretkeyring, FOPRBIN)) == NULL) ! 136: fprintf(pgpout,PSTR("\nCan't open secret key ring file '%s'\n"), ! 137: secretkeyring); ! 138: ! 139: if (!(options & MAINT_SILENT) && *floppyring != '\0' && ! 140: (floppy_fp = fopen(floppyring, FOPRBIN)) == NULL) ! 141: fprintf(pgpout,PSTR("\nCan't open backup key ring file '%s'\n"), ! 142: floppyring); ! 143: ! 144: if ((status = copyfile(f, g, -1L)) < 0) ! 145: { fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"), ringfile); ! 146: goto failed; ! 147: } ! 148: ! 149: if (moreflag && !(options & MAINT_SILENT)) ! 150: open_more(); ! 151: ! 152: setup_trust(); ! 153: if (mverbose) ! 154: fprintf(pgpout, PSTR("\nPass 1: Looking for the \"ultimately-trusted\" keys...\n")); ! 155: rewind(g); ! 156: if ((status = maint_pass1(g)) < 0) ! 157: goto failed; ! 158: ! 159: if (mverbose) ! 160: fprintf(pgpout, PSTR("\nPass 2: Tracing signature chains...\n")); ! 161: rewind(g); ! 162: if ((status = maint_trace_chain(g)) < 0) ! 163: goto failed; ! 164: ! 165: if (!(options & MAINT_SILENT)) ! 166: { if (mverbose) ! 167: fprintf(pgpout, PSTR("\nPass 3: Comparing with original keyring...\n")); ! 168: rewind(f); ! 169: rewind(g); ! 170: if ((status = maint_cmpfiles(f, g)) < 0) ! 171: goto failed; ! 172: } else ! 173: status = 1; ! 174: ! 175: close_more(); ! 176: if (write_error(g)) ! 177: { status = -1; ! 178: goto failed; ! 179: } ! 180: fclose(f); ! 181: fclose(g); ! 182: if (sec_fp) ! 183: fclose(sec_fp); ! 184: if (floppy_fp) ! 185: { fclose(floppy_fp); ! 186: floppy_fp = NULL; ! 187: } ! 188: ! 189: #ifdef DEBUG ! 190: if (check_only) ! 191: { ! 192: if (undefined_trust) ! 193: fprintf(pgpout, "\nKeyring contains %d fully validated key(s) with undefined trust.\n", undefined_trust); ! 194: else ! 195: if (status == 0) ! 196: fprintf(pgpout, "\nMaintenance check OK.\n"); ! 197: rmtemp(tmpring); ! 198: return(0); ! 199: } ! 200: #endif ! 201: ! 202: if (status > 0) /* keyring is changed */ ! 203: { ! 204: if (options & MAINT_SILENT) ! 205: { /* implicit maintenance pass (after pgp -ka, -kr, -ks) */ ! 206: remove(ringfile); ! 207: if (savetemp(tmpring, ringfile) == NULL) ! 208: return(-1); ! 209: } ! 210: else ! 211: { /* explicit maintenance pass */ ! 212: fprintf(pgpout, PSTR("Update public keyring '%s' (Y/n)? "), ringfile); ! 213: if (!getyesno('y')) ! 214: { ! 215: rmtemp(tmpring); ! 216: return(0); ! 217: } ! 218: if (savetempbak(tmpring, ringfile)) ! 219: return(-1); ! 220: } ! 221: } ! 222: else ! 223: rmtemp(tmpring); ! 224: ! 225: return(0); ! 226: ! 227: failed: ! 228: close_more(); ! 229: if (sec_fp) ! 230: fclose(sec_fp); ! 231: if (floppy_fp) ! 232: { fclose(floppy_fp); ! 233: floppy_fp = NULL; ! 234: } ! 235: fclose(f); ! 236: fclose(g); ! 237: #ifdef DEBUG ! 238: savetempbak(tmpring, "tmpring.pub"); ! 239: #else ! 240: rmtemp(tmpring); ! 241: #endif ! 242: return(status); ! 243: } /* maintenance */ ! 244: ! 245: ! 246: /* ! 247: * check if axiomatic keys are present in the secret keyring and ! 248: * clear userid and signature trust bytes ! 249: */ ! 250: int ! 251: maint_pass1(FILE *f) ! 252: { ! 253: int status; ! 254: char userid[256]; ! 255: byte keyID[KEYFRAGSIZE]; ! 256: byte ctb; ! 257: byte keyctrl; ! 258: boolean buckstop = FALSE, show_user = FALSE; ! 259: boolean compromised = FALSE; ! 260: int buckstopcount = 0; ! 261: int usercount = 0; ! 262: long keypos = 0; ! 263: ! 264: while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1) ! 265: { ! 266: if (status == -3) ! 267: return(status); ! 268: if (status < 0) ! 269: continue; ! 270: ! 271: if (is_ctb_type(ctb, CTB_COMMENT_TYPE) || ctb == CTB_KEYCTRL) ! 272: continue; ! 273: if (compromised && is_ctb_type(ctb, CTB_SKE_TYPE) && !usercount) ! 274: continue; /* compromise certificate */ ! 275: ! 276: /* other packets should have trust byte */ ! 277: if (read_trust(f, &keyctrl) < 0) ! 278: return(ERR_NOTRUST); /* not a public keyring */ ! 279: ! 280: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) ! 281: { ! 282: if (compromised = is_compromised(f)) ! 283: keyctrl = KC_OWNERTRUST_NEVER; ! 284: if ((keyctrl & KC_BUCKSTOP)) ! 285: { ! 286: if (check_secretkey(f, keypos) == 0) ! 287: { ! 288: ++buckstopcount; ! 289: buckstop = TRUE; ! 290: if (mverbose) ! 291: fprintf(pgpout, "* %s",keyIDstring(keyID)); ! 292: } ! 293: else ! 294: { /* not in secret keyring */ ! 295: keyctrl &= ~KC_BUCKSTOP; ! 296: if (TRUST_LEV(keyctrl) == KC_OWNERTRUST_ULTIMATE) ! 297: keyctrl = KC_OWNERTRUST_ALWAYS; ! 298: if (mverbose) ! 299: fprintf(pgpout, ". %s",keyIDstring(keyID)); ! 300: } ! 301: show_user = mverbose; ! 302: } ! 303: else ! 304: { ! 305: buckstop = FALSE; ! 306: show_user = FALSE; ! 307: } ! 308: usercount = 0; ! 309: keyctrl &= ~KC_VISITED; ! 310: ! 311: } ! 312: else if (ctb == CTB_USERID) ! 313: { ! 314: if (show_user) ! 315: { ! 316: if (usercount) /* more than one user ID */ ! 317: fprintf(pgpout, " "); ! 318: fprintf(pgpout, " %s\n", LOCAL_CHARSET(userid)); ! 319: } ! 320: keyctrl &= ~KC_LEGIT_MASK; ! 321: if (buckstop) ! 322: keyctrl |= KC_LEGIT_COMPLETE; ! 323: else ! 324: keyctrl |= KC_LEGIT_UNKNOWN; ! 325: ++usercount; ! 326: } ! 327: else if (is_ctb_type(ctb, CTB_SKE_TYPE)) ! 328: { ! 329: keyctrl = KC_SIGTRUST_UNDEFINED; ! 330: } ! 331: fseek(f, -1L, SEEK_CUR); ! 332: fwrite(&keyctrl, 1, 1, f); ! 333: fseek(f, 0L, SEEK_CUR); ! 334: keypos = ftell(f); ! 335: } ! 336: if (buckstopcount == 0 && mverbose) ! 337: { ! 338: fprintf(pgpout, PSTR("No ultimately-trusted keys.\n")); ! 339: } ! 340: return(0); ! 341: } ! 342: ! 343: ! 344: /* ! 345: * scan keyring for buckstop keys and start the recursive trace_sig_chain() ! 346: * on them ! 347: */ ! 348: int ! 349: maint_trace_chain(FILE *f) ! 350: { ! 351: int status; ! 352: char userid[256]; ! 353: byte keyID[KEYFRAGSIZE]; ! 354: long trustpos = 0; ! 355: byte ctb; ! 356: byte own_trust; ! 357: boolean buckstop = FALSE; ! 358: ! 359: while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1) ! 360: { ! 361: if (status == -3) ! 362: return(status); ! 363: if (status < 0) ! 364: continue; ! 365: ! 366: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) ! 367: { ! 368: trustpos = ftell(f); ! 369: if ((status = read_trust(f, &own_trust)) < 0) ! 370: return(status); ! 371: buckstop = (own_trust & KC_BUCKSTOP) != 0; ! 372: userid[0] = '\0'; ! 373: } ! 374: else if (ctb == CTB_USERID) ! 375: { ! 376: if (buckstop) ! 377: { ! 378: buckstop = FALSE; /* only for first user id */ ! 379: if (mverbose) ! 380: fprintf(pgpout, "* %s\n", LOCAL_CHARSET(userid)); ! 381: ! 382: if (TRUST_LEV(own_trust) == KC_OWNERTRUST_UNDEFINED) ! 383: { SET_TRUST(&own_trust, ask_owntrust(userid, own_trust)); ! 384: write_trust_pos(f, own_trust, trustpos); ! 385: } ! 386: if (trace_sig_chain(f, keyID, TRUST_LEV(own_trust), 0) < 0) ! 387: return(-1); ! 388: } ! 389: } ! 390: } ! 391: return(0); ! 392: } ! 393: ! 394: ! 395: /* ! 396: * check if the maintenance pass changed anything ! 397: * returns 0 if files f and g are equal and the number of changed ! 398: * trust bytes if the files are different or a negative value on error ! 399: */ ! 400: int ! 401: maint_cmpfiles(FILE *f, FILE *g) ! 402: { ! 403: int status; ! 404: char userid[256]; ! 405: byte keyID[KEYFRAGSIZE]; ! 406: byte sigkeyID[KEYFRAGSIZE]; ! 407: byte ctb; ! 408: byte kc_orig, kc_new; ! 409: int usercount = 0; ! 410: int changed = 0; ! 411: ! 412: fprintf(pgpout, PSTR(" KeyID Trust Validity User ID\n")); ! 413: while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) ! 414: { ! 415: if (status == -3) ! 416: break; ! 417: if (status < 0) ! 418: continue; ! 419: if (is_ctb_type(ctb, CTB_COMMENT_TYPE)) ! 420: continue; ! 421: /* unexpected trust packet, probably after version error */ ! 422: if (ctb == CTB_KEYCTRL) ! 423: continue; ! 424: ! 425: /* other packets should have trust byte */ ! 426: fseek(g, ftell(f), SEEK_SET); ! 427: if (read_trust(f, &kc_orig) < 0 || read_trust(g, &kc_new) < 0) ! 428: { status = ERR_NOTRUST; ! 429: break; ! 430: } ! 431: ! 432: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) ! 433: { ! 434: if (is_compromised(f)) ! 435: { ! 436: fprintf(pgpout, "# "); ! 437: nextkeypacket(f, &ctb); /* skip compromise certificate */ ! 438: nextkeypacket(g, &ctb); ! 439: } ! 440: else if ((kc_new & KC_BUCKSTOP)) ! 441: fprintf(pgpout, "* "); ! 442: else ! 443: fprintf(pgpout, " "); ! 444: ! 445: fprintf(pgpout, "%s ",keyIDstring(keyID)); ! 446: changed += show_trust(kc_new, kc_orig); ! 447: usercount = 0; ! 448: userid[0] = '\0'; ! 449: } ! 450: else if (ctb == CTB_USERID) ! 451: { ! 452: if (usercount) /* more than one user ID */ ! 453: fprintf(pgpout, " %*s ", trustlst_len, ""); ! 454: ++usercount; ! 455: changed += show_legit(kc_new, kc_orig); ! 456: fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid)); ! 457: } ! 458: else if (is_ctb_type(ctb, CTB_SKE_TYPE)) ! 459: { ! 460: if (kc_new & KC_CONTIG) ! 461: fprintf(pgpout, "c "); ! 462: else ! 463: fprintf(pgpout, " "); ! 464: changed += show_trust(kc_new, kc_orig); ! 465: fprintf(pgpout, "%*s ", legitlst_len, ""); ! 466: show_userid(f, sigkeyID); ! 467: } ! 468: } ! 469: if (status >= -1 && changed) ! 470: fprintf(pgpout, PSTR("\n%d \"trust parameter(s)\" changed.\n"), changed); ! 471: if (status < -1) /* -1 is OK, EOF */ ! 472: return(status); ! 473: return(changed); ! 474: } /* maint_cmpfiles */ ! 475: ! 476: ! 477: /* ! 478: * translate the messages in the arrays trust_lst and legit_lst. ! 479: * trustlst_len and legitlst_len will be set to the length of ! 480: * the longest translated string. ! 481: */ ! 482: void ! 483: init_trust_lst() ! 484: { ! 485: static int initialized = 0; ! 486: int i, len; ! 487: char *s; ! 488: ! 489: if (initialized) ! 490: return; ! 491: for (i = 0; i < 8; ++i) ! 492: { if (trust_lst[i][0]) ! 493: { s = PSTR (trust_lst[i]); ! 494: if (s != trust_lst[i]) ! 495: strncpy(trust_lst[i], s, sizeof(trust_lst[0]) - 1); ! 496: len = strlen(s); ! 497: if (len > trustlst_len) ! 498: trustlst_len = len; ! 499: } ! 500: } ! 501: for (i = 0; i < 4; ++i) ! 502: { s = PSTR (legit_lst[i]); ! 503: if (s != legit_lst[i]) ! 504: strncpy(legit_lst[i], s, sizeof(legit_lst[0]) - 1); ! 505: len = strlen(s); ! 506: if (len > legitlst_len) ! 507: legitlst_len = len; ! 508: } ! 509: ++trustlst_len; ! 510: ++legitlst_len; ! 511: initialized = 1; ! 512: } /* init_trust_lst */ ! 513: ! 514: /* ! 515: * show the trust level of trust byte kc_new. If it is ! 516: * different from the old level (kc_orig) the print a '!' before ! 517: * the level string ! 518: */ ! 519: int ! 520: show_trust(byte kc_new, byte kc_orig) ! 521: { ! 522: #ifdef DEBUG ! 523: fprintf(pgpout, " %02x", kc_new); ! 524: if (kc_new != kc_orig) ! 525: { ! 526: fprintf(pgpout, " (%02x) ", kc_orig); ! 527: return(1); ! 528: } ! 529: fprintf(pgpout, " "); ! 530: return(0); ! 531: #else ! 532: init_trust_lst(); ! 533: fprintf(pgpout, "%c%-*s", (kc_new == kc_orig ? ' ' : '!'), ! 534: trustlst_len, trust_lst[TRUST_LEV(kc_new)]); ! 535: return(kc_new != kc_orig); ! 536: #endif ! 537: } /* show_trust */ ! 538: ! 539: /* ! 540: * show_legit is the same as show_trust, only it uses legit_lst ! 541: * for messages ! 542: */ ! 543: int ! 544: show_legit(byte kc_new, byte kc_orig) ! 545: { ! 546: #ifdef DEBUG ! 547: return(show_trust(kc_new, kc_orig)); ! 548: #else ! 549: init_trust_lst(); ! 550: kc_new &= KC_LEGIT_MASK; ! 551: kc_orig &= KC_LEGIT_MASK; ! 552: fprintf(pgpout, "%c%-*s", (kc_new == kc_orig ? ' ' : '!'), ! 553: legitlst_len, legit_lst[kc_new]); ! 554: return(kc_new != kc_orig); ! 555: #endif ! 556: } /* show_legit */ ! 557: ! 558: ! 559: /* ! 560: * Find all signatures made with a key, fromID is the keyID of this key ! 561: * owner_trust is the trust level of this key. ! 562: * If a trusted signature makes a key fully legit then signatures made ! 563: * with this key are also recursively traced on down the tree. ! 564: * ! 565: * The file f is the public keyring, it must be open for update. ! 566: * depth is the level of recursion, it is used to indent the userIDs ! 567: * and to check if we don't exceed the limit "max_cert_depth" ! 568: * ! 569: * fromID should be the keyID of a fully validated key. ! 570: */ ! 571: int ! 572: trace_sig_chain(FILE *f, byte *fromID, int owner_trust, int depth) ! 573: { ! 574: long filepos; ! 575: int status; ! 576: int trust_count = 0; ! 577: byte keyID[KEYFRAGSIZE]; ! 578: byte sigkeyID[KEYFRAGSIZE]; ! 579: byte ctb; ! 580: byte own_trust, sig_trust; ! 581: char userid[256]; ! 582: int sig_count = 0; ! 583: int compromised = 0; ! 584: long usertrustpos = 0; ! 585: long ownt_pos = 0; ! 586: boolean fromsig = FALSE; ! 587: ! 588: #ifdef DEBUG ! 589: if (mverbose) ! 590: fprintf(pgpout, "%*s--- %s\n", 2*depth, "", keyIDstring(fromID)); ! 591: #endif ! 592: filepos = ftell(f); ! 593: rewind(f); ! 594: userid[0] = '\0'; ! 595: while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) ! 596: { ! 597: if (status == -3) ! 598: return(status); ! 599: if (status < 0) ! 600: continue; ! 601: ! 602: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) ! 603: { ! 604: compromised = is_compromised(f); ! 605: ownt_pos = ftell(f); ! 606: if (read_trust(f, &own_trust)) ! 607: return(ERR_NOTRUST); ! 608: userid[0] = '\0'; ! 609: } ! 610: else if (ctb == CTB_USERID) ! 611: { ! 612: usertrustpos = ftell(f); ! 613: trust_count = 0; ! 614: fromsig = FALSE; ! 615: } ! 616: else if (is_ctb_type(ctb, CTB_SKE_TYPE)) ! 617: { /* signature packet */ ! 618: if (compromised) ! 619: continue; ! 620: read_trust(f, &sig_trust); ! 621: /* we're looking for signatures made by "fromID" */ ! 622: if (memcmp(sigkeyID, fromID, sizeof(sigkeyID)) == 0) ! 623: { ! 624: ++sig_count; ! 625: if (mverbose) ! 626: fprintf(pgpout, "%*s > %s\n", 2*depth, "", ! 627: LOCAL_CHARSET(userid)); ! 628: if (TRUST_LEV(sig_trust) != owner_trust) ! 629: { ! 630: SET_TRUST(&sig_trust, owner_trust); ! 631: } ! 632: sig_trust |= KC_CONTIG; ! 633: fseek(f, -1L, SEEK_CUR); ! 634: fwrite(&sig_trust, 1, 1, f); ! 635: fseek(f, 0L, SEEK_CUR); ! 636: fromsig = TRUE; ! 637: } ! 638: ! 639: if (sig_trust & KC_CONTIG) ! 640: { ! 641: trust_count += TRUST_FAC(sig_trust); ! 642: ! 643: if (fromsig) /* fromID has signed this key */ ! 644: { ! 645: switch (set_legit(f, usertrustpos, trust_count)) ! 646: { ! 647: case -1: return(-1); ! 648: case 1: /* this signature made the key fully valid */ ! 649: if ((own_trust & (KC_BUCKSTOP|KC_VISITED)) == 0) ! 650: { ! 651: if (TRUST_LEV(own_trust) == KC_OWNERTRUST_UNDEFINED) ! 652: SET_TRUST(&own_trust, ask_owntrust(userid, own_trust)); ! 653: if (depth < max_cert_depth) ! 654: own_trust |= KC_VISITED; ! 655: write_trust_pos(f, own_trust, ownt_pos); ! 656: if (depth < max_cert_depth) ! 657: trace_sig_chain(f, keyID, TRUST_LEV(own_trust), depth+1); ! 658: } ! 659: } ! 660: } ! 661: } ! 662: } ! 663: } ! 664: #ifdef DEBUG ! 665: if (mverbose && sig_count == 0) /* no signatures from this user */ ! 666: fprintf(pgpout, PSTR("%*s (No signatures)\n"), 2*depth, ""); ! 667: if (mverbose) ! 668: fprintf(pgpout, "%*s--- %s\n", 2*depth, "", keyIDstring(fromID)); ! 669: #endif ! 670: fseek(f, filepos, SEEK_SET); ! 671: return(0); ! 672: } /* trace_sig_chain */ ! 673: ! 674: ! 675: /* ! 676: * compare the key in file f at keypos with the matching key in the ! 677: * secret keyring, the global variable sec_fp must contain the file pointer ! 678: * for of the secret keyring. ! 679: * ! 680: * returns 1 if the key was not found, -2 if the keys were different ! 681: * and 0 if the keys compared OK ! 682: */ ! 683: int ! 684: check_secretkey(FILE *f, long keypos) ! 685: { ! 686: int status = -1; ! 687: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 688: unit nsec[MAX_UNIT_PRECISION], esec[MAX_UNIT_PRECISION]; ! 689: char userid[256]; ! 690: byte keyID[KEYFRAGSIZE]; ! 691: long savepos, pktlen; ! 692: byte ctb; ! 693: ! 694: if (sec_fp == NULL) ! 695: return(-1); ! 696: ! 697: savepos = ftell(f); ! 698: fseek(f, keypos, SEEK_SET); ! 699: if (readkeypacket(f, FALSE, &ctb, NULL, NULL, n, e, ! 700: NULL, NULL, NULL, NULL, NULL, NULL) < 0) ! 701: goto ex; ! 702: extract_keyID(keyID, n); ! 703: ! 704: do /* get userid */ ! 705: { status = readkpacket(f, &ctb, userid, NULL, NULL); ! 706: if (status == -1 || status == -3) ! 707: goto ex; ! 708: } while (ctb != CTB_USERID); ! 709: ! 710: if (lookup_by_keyID(sec_fp, keyID) < 0) ! 711: { ! 712: #if 0 ! 713: if (!check_only) ! 714: { ! 715: fprintf(pgpout, PSTR ( ! 716: "\nAn \"axiomatic\" key is one which does not need certifying by\n\ ! 717: anyone else. Usually this special status is reserved only for your\n\ ! 718: own keys, which should also appear on your secret keyring. The owner\n\ ! 719: of an axiomatic key (who is typically yourself) is \"ultimately trusted\"\n\ ! 720: by you to certify any or all other keys.\n")); ! 721: fprintf(pgpout, PSTR ("\nKey for user ID: \"%s\"\n\ ! 722: is designated as an \"ultimately-trusted\" introducer, but the key\n\ ! 723: does not appear in the secret keyring.\n\ ! 724: Use this key as an ultimately-trusted introducer (y/N)? "), ! 725: LOCAL_CHARSET(userid)); ! 726: status = (getyesno('n') ? 0 : 1); ! 727: } ! 728: #else ! 729: status = 1; ! 730: #endif ! 731: } ! 732: else ! 733: { ! 734: long kpos = ftell(sec_fp); ! 735: if (readkeypacket(sec_fp, FALSE, &ctb, NULL, NULL, nsec, esec, ! 736: NULL, NULL, NULL, NULL, NULL, NULL) < 0) ! 737: { ! 738: fprintf(pgpout, PSTR("\n\007Cannot read from secret keyring.\n")); ! 739: status = -3; ! 740: goto ex; ! 741: } ! 742: if (mp_compare(n, nsec) || mp_compare(e, esec)) ! 743: { /* Red Alert! */ ! 744: fprintf(pgpout, PSTR("\n\007WARNING: Public key for user ID: \"%s\"\n\ ! 745: does not match the corresponding key in the secret keyring.\n"), ! 746: LOCAL_CHARSET(userid)); ! 747: fprintf(pgpout, PSTR("This is a serious condition, indicating possible keyring tampering.\n")); ! 748: status = -2; ! 749: } ! 750: else ! 751: status = 0; ! 752: ! 753: if (floppy_fp) ! 754: { ! 755: if (lookup_by_keyID(floppy_fp, keyID) < 0) ! 756: { ! 757: fprintf(pgpout, PSTR("Public key for: \"%s\"\n\ ! 758: is not present in the backup keyring '%s'.\n"), ! 759: LOCAL_CHARSET(userid), floppyring); ! 760: } ! 761: else ! 762: { ! 763: pktlen = ftell(sec_fp) - kpos; ! 764: fseek(sec_fp, kpos, SEEK_SET); ! 765: while (--pktlen >= 0 && getc(sec_fp) == getc(floppy_fp)) ; ! 766: if (pktlen != -1) ! 767: { ! 768: fprintf(pgpout, PSTR("\n\007WARNING: Secret key for: \"%s\"\n\ ! 769: does not match the key in the backup keyring '%s'.\n"), ! 770: LOCAL_CHARSET(userid), floppyring); ! 771: fprintf(pgpout, PSTR("This is a serious condition, indicating possible keyring tampering.\n")); ! 772: status = -2; ! 773: } ! 774: } ! 775: } ! 776: } ! 777: ex: ! 778: fseek(f, savepos, SEEK_SET); ! 779: return(status); ! 780: } /* check_secretkey */ ! 781: ! 782: ! 783: /* ! 784: * setup tables for trust scoring. ! 785: */ ! 786: void ! 787: setup_trust() ! 788: { /* initialize trust table */ ! 789: if (marg_min == 0) /* marginally trusted signatures are ignored */ ! 790: { ! 791: trust_tbl[5] = 0; ! 792: trust_tbl[6] = 1; ! 793: complete_min = compl_min; ! 794: } ! 795: else ! 796: { ! 797: if (marg_min < compl_min) ! 798: marg_min = compl_min; ! 799: trust_tbl[5] = compl_min; ! 800: trust_tbl[6] = marg_min; ! 801: complete_min = compl_min * marg_min; ! 802: } ! 803: trust_tbl[7] = complete_min; /* ultimate trust */ ! 804: marginal_min = complete_min / 2; ! 805: } /* setup_trust */ ! 806: ! 807: ! 808: /* ! 809: * set valid level of a userid, computed from trust_count. ! 810: * returns 1 if the key/userid pair is fully legit. ! 811: */ ! 812: int ! 813: set_legit(FILE *f, long trustpos, int trust_count) ! 814: { ! 815: long filepos; ! 816: byte keyctrl; ! 817: ! 818: filepos = ftell(f); ! 819: fseek(f, trustpos, SEEK_SET); /* user id trust byte */ ! 820: if (read_trust(f, &keyctrl) < 0) ! 821: return(-1); ! 822: ! 823: keyctrl &= ~KC_LEGIT_MASK; ! 824: if (trust_count < marginal_min) ! 825: keyctrl |= KC_LEGIT_UNTRUSTED; ! 826: else if (trust_count < complete_min) ! 827: keyctrl |= KC_LEGIT_MARGINAL; ! 828: else ! 829: keyctrl |= KC_LEGIT_COMPLETE; ! 830: ! 831: fseek(f, trustpos, SEEK_SET); ! 832: write_trust(f, keyctrl); ! 833: ! 834: fseek(f, filepos, SEEK_SET); ! 835: ! 836: if ((keyctrl & KC_LEGIT_MASK) == KC_LEGIT_COMPLETE) ! 837: return(1); ! 838: else ! 839: return(0); ! 840: } /* set_legit */ ! 841: ! 842: ! 843: int ask_owntrust(char *userid, byte cur_trust) ! 844: /* Ask for a wetware decision from the human on how much to trust ! 845: this key's owner to certify other keys. Returns trust value. */ ! 846: { ! 847: char buf[8]; ! 848: ! 849: if (check_only) ! 850: { ++undefined_trust; ! 851: return(KC_OWNERTRUST_UNDEFINED); ! 852: } ! 853: ! 854: fprintf(pgpout, ! 855: PSTR("\nMake a determination in your own mind whether this key actually\n\ ! 856: belongs to the person whom you think it belongs to, based on available\n\ ! 857: evidence. If you think it does, then based on your estimate of\n\ ! 858: that person's integrity and competence in key management, answer\n\ ! 859: the following question:\n")); ! 860: fprintf(pgpout, PSTR("\nWould you trust \"%s\"\n\ ! 861: to act as an introducer and certify other people's public keys to you?\n\ ! 862: (1=I don't know. 2=No. 3=Usually. 4=Yes, always.) ? "), ! 863: LOCAL_CHARSET(userid)); ! 864: fflush(pgpout); ! 865: getstring(buf, sizeof(buf)-1, TRUE); ! 866: switch (buf[0]) ! 867: { case '1': return KC_OWNERTRUST_UNKNOWN; ! 868: case '2': return KC_OWNERTRUST_NEVER; ! 869: case '3': return KC_OWNERTRUST_USUALLY; ! 870: case '4': return KC_OWNERTRUST_ALWAYS; ! 871: default: return(TRUST_LEV(cur_trust)); ! 872: } ! 873: } /* ask_owntrust */ ! 874: ! 875: ! 876: /* ! 877: * compare all key packets in keyring file f with file g ! 878: * XXX: untested ! 879: */ ! 880: int ! 881: keyring_cmp(FILE *f, FILE *g) ! 882: { ! 883: int status, error = 0, badkeys = 0; ! 884: byte ctb; ! 885: byte keyID[KEYFRAGSIZE]; ! 886: char userid[256]; ! 887: long pktlen, keypos = 0; ! 888: ! 889: rewind(f); ! 890: while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1) ! 891: { ! 892: if (status == -3) ! 893: return(status); ! 894: if (status < 0) ! 895: continue; ! 896: if (is_key_ctb(ctb)) ! 897: { ! 898: pktlen = ftell(f) - keypos; ! 899: fseek(f, keypos, SEEK_SET); ! 900: if (lookup_by_keyID(g, keyID) < 0) ! 901: { ! 902: error = 1; ! 903: continue; ! 904: } ! 905: while (--pktlen >= 0 && getc(f) == getc(g)) ; ! 906: if (pktlen != -1) ! 907: { ! 908: error = 2; ! 909: ++badkeys; ! 910: } ! 911: ! 912: } ! 913: if (error && ctb == CTB_USERID) ! 914: { ! 915: switch (error) { ! 916: case 1: fprintf(pgpout, PSTR("\n\007Key for user ID \"%s\"\n\ ! 917: is not present in backup keyring\n"), LOCAL_CHARSET(userid)); ! 918: case 2: fprintf(pgpout, PSTR("\n\007Key for user ID \"%s\"\n\ ! 919: does not match key in backup keyring\n"), LOCAL_CHARSET(userid)); ! 920: } ! 921: error = 0; ! 922: } ! 923: keypos = ftell(f); ! 924: } ! 925: if (error) ! 926: status = -5; ! 927: return(status < 0 ? status : badkeys); ! 928: } /* keyring_cmp */ ! 929: ! 930: ! 931: /* ! 932: * stripped down version of readkeypacket(), the output userid ! 933: * is a null terminated string. ! 934: */ ! 935: int ! 936: readkpacket(FILE *f, byte *ctb, char *userid, byte *keyID, byte *sigkeyID) ! 937: { ! 938: int status; ! 939: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 940: ! 941: status = readkeypacket(f, FALSE, ctb, NULL, userid, n, e, ! 942: NULL, NULL, NULL, NULL, sigkeyID, NULL); ! 943: ! 944: if (status < 0) ! 945: { ! 946: #ifdef DEBUG ! 947: if (status < -1) ! 948: fprintf(stderr, "readkeypacket returned %d\n", status); ! 949: #endif ! 950: return(status); ! 951: } ! 952: ! 953: if (keyID && is_key_ctb(*ctb)) ! 954: extract_keyID(keyID, n); ! 955: ! 956: if (userid && *ctb == CTB_USERID) ! 957: PascalToC(userid); ! 958: ! 959: return(0); ! 960: } /* readkpacket */ ! 961: ! 962: ! 963: /* ! 964: * scan keyfile f for keyID srch_keyID. ! 965: * returns the file position of the key if it is found, and sets the ! 966: * file pointer to the start of the key packet. ! 967: * returns -1 if the key was not found or < -1 if there was an error ! 968: */ ! 969: long ! 970: lookup_by_keyID(FILE *f, byte *srch_keyID) ! 971: { ! 972: int status; ! 973: long keypos = 0; ! 974: byte keyID[KEYFRAGSIZE]; ! 975: byte ctb; ! 976: ! 977: rewind(f); ! 978: while ((status = readkpacket(f, &ctb, NULL, keyID, NULL)) != -1) ! 979: { ! 980: if (status == -3) ! 981: break; ! 982: if (status < 0) ! 983: continue; ! 984: if (is_key_ctb(ctb) && memcmp(keyID, srch_keyID, KEYFRAGSIZE) == 0) ! 985: { ! 986: fseek(f, keypos, SEEK_SET); ! 987: return(keypos); ! 988: } ! 989: keypos = ftell(f); ! 990: } ! 991: return(status); ! 992: } /* lookup_by_keyID */ ! 993: ! 994: ! 995: /* ! 996: * look up the key matching "keyID" and print the first userID ! 997: * of this key. File position of f is saved. ! 998: */ ! 999: void ! 1000: show_userid(FILE *f, byte *keyID) ! 1001: { ! 1002: int status; ! 1003: long filepos; ! 1004: char userid[256]; ! 1005: byte ctb; ! 1006: ! 1007: filepos = ftell(f); ! 1008: if (lookup_by_keyID(f, keyID) >= 0) ! 1009: while ((status = readkpacket(f, &ctb, userid, NULL, NULL)) != -1 && status != -3) ! 1010: if (ctb == CTB_USERID) ! 1011: { ! 1012: fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid)); ! 1013: fseek(f, filepos, SEEK_SET); ! 1014: return; ! 1015: } ! 1016: ! 1017: fprintf(pgpout, "(KeyID: %s)\n",keyIDstring(keyID)); ! 1018: fseek(f, filepos, SEEK_SET); ! 1019: } /* show_userid */ ! 1020: ! 1021: /* ! 1022: * show the key in file f at file position keypos. ! 1023: * 'what' controls the info that will be shown: ! 1024: * SHOW_TRUST: show trust byte info ! 1025: * SHOW_SIGS: show signatures ! 1026: * these constants can be or'ed to get both ! 1027: */ ! 1028: int ! 1029: show_key(FILE *f, long keypos, int what) ! 1030: { ! 1031: int status; ! 1032: long filepos; ! 1033: char userid[256]; ! 1034: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1035: byte sigkeyID[KEYFRAGSIZE]; ! 1036: word32 timestamp; ! 1037: byte ctb, keyctrl; ! 1038: int userids = 0; ! 1039: boolean print_trust = FALSE; ! 1040: int precision = global_precision; ! 1041: ! 1042: filepos = ftell(f); ! 1043: fseek(f, keypos, SEEK_SET); ! 1044: while ((status = readkeypacket(f, FALSE, &ctb, (byte *)×tamp, userid, ! 1045: n, e, NULL, NULL, NULL, NULL, sigkeyID, &keyctrl)) == 0) ! 1046: { ! 1047: if (is_key_ctb(ctb)) ! 1048: { if (userids) ! 1049: break; ! 1050: } ! 1051: else if (ctb == CTB_KEYCTRL) /* trust bytes only in public keyrings */ ! 1052: { ! 1053: if (what & SHOW_TRUST) ! 1054: print_trust = TRUE; ! 1055: } ! 1056: else if (ctb == CTB_USERID) ! 1057: { if (userids == 0) ! 1058: { PascalToC(userid); /* for display */ ! 1059: fprintf(pgpout,PSTR("\nKey for user ID: %s\n"), ! 1060: LOCAL_CHARSET(userid)); ! 1061: fprintf(pgpout,PSTR("%d-bit key, Key ID %s, created %s\n"), ! 1062: countbits(n), key2IDstring(n), cdate(×tamp) ); ! 1063: if (print_trust) ! 1064: { ! 1065: switch (TRUST_LEV(keyctrl)) ! 1066: { ! 1067: case KC_OWNERTRUST_UNDEFINED: ! 1068: case KC_OWNERTRUST_UNKNOWN: ! 1069: /* Just don't say anything in this case */ ! 1070: break; ! 1071: case KC_OWNERTRUST_NEVER: /* untrusted */ ! 1072: fprintf(pgpout, PSTR("This user is untrusted to certify other keys.\n")); ! 1073: break; ! 1074: case KC_OWNERTRUST_USUALLY: /* marginal trust */ ! 1075: fprintf(pgpout, PSTR("This user is generally trusted to certify other keys.\n")); ! 1076: break; ! 1077: case KC_OWNERTRUST_ALWAYS: /* complete trust */ ! 1078: fprintf(pgpout, PSTR("This user is completely trusted to certify other keys.\n")); ! 1079: break; ! 1080: case KC_OWNERTRUST_ULTIMATE: /* axiomatic, ultimate trust */ ! 1081: fprintf(pgpout, PSTR("This axiomatic key is ultimately trusted to certify other keys.\n")); ! 1082: break; ! 1083: default: ! 1084: break; ! 1085: } /* switch */ ! 1086: } ! 1087: ++userids; ! 1088: } ! 1089: else ! 1090: { PascalToC(userid); ! 1091: if (what != 0) ! 1092: fprintf(pgpout, "\n"); ! 1093: fprintf(pgpout,PSTR("Also known as: %s\n"), ! 1094: LOCAL_CHARSET(userid)); ! 1095: } ! 1096: if (print_trust) ! 1097: { ! 1098: read_trust(f, &keyctrl); ! 1099: switch (keyctrl & KC_LEGIT_MASK) ! 1100: { ! 1101: case 0: /* undefined certification level */ ! 1102: case 1: /* uncertified */ ! 1103: fprintf(pgpout, PSTR("This key/userID association is not certified.\n")); ! 1104: break; ! 1105: case 2: /* marginal certification */ ! 1106: fprintf(pgpout, PSTR("This key/userID association is marginally certified.\n")); ! 1107: break; ! 1108: case 3: /* complete certification */ ! 1109: fprintf(pgpout, PSTR("This key/userID association is fully certified.\n")); ! 1110: break; ! 1111: default: /* can't get here, right? */ ! 1112: break; ! 1113: } /* switch */ ! 1114: } /* print_trust */ ! 1115: } ! 1116: else if ((what & SHOW_SIGS) && is_ctb_type(ctb, CTB_SKE_TYPE)) ! 1117: { ! 1118: if (print_trust) ! 1119: { ! 1120: read_trust(f, &keyctrl); ! 1121: switch (TRUST_LEV(keyctrl)) ! 1122: { ! 1123: case KC_SIGTRUST_UNDEFINED: /* undefined trust level */ ! 1124: case KC_SIGTRUST_UNKNOWN: ! 1125: /* Just don't say anything in this case */ ! 1126: fprintf(pgpout, PSTR(" Questionable certification from:\n ")); ! 1127: break; ! 1128: case KC_SIGTRUST_UNTRUSTED: /* untrusted */ ! 1129: fprintf(pgpout, PSTR(" Untrusted certification from:\n ")); ! 1130: break; ! 1131: case KC_SIGTRUST_MARGINAL: /* marginal trust */ ! 1132: fprintf(pgpout, PSTR(" Generally trusted certification from:\n ")); ! 1133: break; ! 1134: case KC_SIGTRUST_COMPLETE: /* complete trust */ ! 1135: fprintf(pgpout, PSTR(" Completely trusted certification from:\n ")); ! 1136: break; ! 1137: case KC_SIGTRUST_ULTIMATE: /* axiomatic, ultimate trust */ ! 1138: fprintf(pgpout, PSTR(" Axiomatically trusted certification from:\n ")); ! 1139: break; ! 1140: default: /* can't get here, right? */ ! 1141: break; ! 1142: } /* switch */ ! 1143: } ! 1144: else ! 1145: fprintf(pgpout, PSTR(" Certified by: ")); ! 1146: show_userid(f, sigkeyID); ! 1147: } ! 1148: } ! 1149: if (status == -1 && userids) ! 1150: status = 0; ! 1151: set_precision(precision); ! 1152: fseek(f, filepos, SEEK_SET); ! 1153: return(status); ! 1154: } /* show_key */ ! 1155: ! 1156: ! 1157: /* ! 1158: * write trust byte "keyctrl" to file f at file position "pos" ! 1159: */ ! 1160: void ! 1161: write_trust_pos(FILE *f, byte keyctrl, long pos) ! 1162: { ! 1163: long fpos; ! 1164: ! 1165: fpos = ftell(f); ! 1166: fseek(f, pos, SEEK_SET); ! 1167: write_trust(f, keyctrl); ! 1168: fseek(f, fpos, SEEK_SET); ! 1169: } /* write_trust_pos */ ! 1170: ! 1171: ! 1172: /* ! 1173: * read a trust byte packet from file f, the trust byte will be ! 1174: * stored in "keyctrl". ! 1175: * returns -1 on EOF, -3 on corrupt input, and ERR_NOTRUST if ! 1176: * the packet was not a trust byte (this can be used to check if ! 1177: * a file is a keyring (with trust bytes) or a keyfile). ! 1178: */ ! 1179: int ! 1180: read_trust(FILE *f, byte *keyctrl) ! 1181: { ! 1182: unsigned char buf[3]; ! 1183: ! 1184: if (fread(buf, 1, 3, f) != 3) ! 1185: return -1; ! 1186: if (buf[0] != CTB_KEYCTRL) ! 1187: { ! 1188: if (is_ctb(buf[0])) ! 1189: return(ERR_NOTRUST); ! 1190: else ! 1191: return(-3); /* bad data */ ! 1192: } ! 1193: if (buf[1] != 1) /* length must be 1 */ ! 1194: return(-3); ! 1195: if (keyctrl) ! 1196: *keyctrl = buf[2]; ! 1197: return(0); ! 1198: } /* read_trust */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.