|
|
1.1.1.8 ! 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-1996 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: Note that while most PGP source modules bear Philip Zimmermann's ! 10: copyright notice, many of them have been revised or entirely written ! 11: by contributors who frequently failed to put their names in their ! 12: code. Code that has been incorporated into PGP from other authors ! 13: was either originally published in the public domain or is used with ! 14: permission from the various authors. ! 15: ! 16: PGP is available for free to the public under certain restrictions. ! 17: See the PGP User's Guide (included in the release package) for ! 18: important information about licensing, patent restrictions on ! 19: certain algorithms, trademarks, copyrights, and export controls. ! 20: ! 21: keymaint.c implemented by Branko Lankester. ! 22: */ ! 23: ! 24: #include <stdio.h> ! 25: #include <time.h> ! 26: #include <stdlib.h> ! 27: #include "mpilib.h" ! 28: #include "random.h" ! 29: #include "crypto.h" ! 30: #include "fileio.h" ! 31: #include "keymgmt.h" ! 32: #include "keymaint.h" ! 33: #include "mpiio.h" ! 34: #include "charset.h" ! 35: #include "language.h" ! 36: #include "pgp.h" ! 37: #ifdef MACTC5 ! 38: #include "Macutil3.h" ! 39: #include "PGPDialogs.h" ! 40: #include "MyBufferedStdio.h" ! 41: #include "ReplaceStdio.h" ! 42: #endif ! 43: ! 44: #if 1 /* def DEBUG */ ! 45: #include <assert.h> ! 46: #else ! 47: #define assert(x) ! 48: #endif ! 49: ! 50: /* Helper functions to work on newkey lists */ ! 51: void free_newkeys(struct newkey *nkeys) ! 52: { ! 53: struct newkey *nkey; ! 54: ! 55: while (nkeys) { ! 56: nkey = nkeys; ! 57: nkeys = nkeys->next; ! 58: free(nkey); ! 59: } ! 60: } ! 61: ! 62: int ismember_newkeys(byte const keyid[KEYFRAGSIZE], struct newkey const *nkeys) ! 63: { ! 64: while (nkeys) { ! 65: if (memcmp(keyid, nkeys->keyID, KEYFRAGSIZE) == 0) ! 66: return 1; ! 67: nkeys = nkeys->next; ! 68: } ! 69: return 0; ! 70: } ! 71: ! 72: /* The main checking code... */ ! 73: ! 74: struct userid; ! 75: struct signature; ! 76: ! 77: struct pubkey { ! 78: struct pubkey *pk_next; ! 79: struct pubkey *pk_hash; /* hash list for keyID */ ! 80: struct userid *pk_userids; ! 81: struct signature *pk_signed; /* signatures this key made */ ! 82: byte pk_keyid[KEYFRAGSIZE]; ! 83: byte pk_owntrust; ! 84: byte pk_depth; /* shortest cert. path to buckstop key */ ! 85: }; ! 86: ! 87: struct userid { ! 88: struct userid *uid_next; ! 89: struct pubkey *uid_key; /* backlink to key */ ! 90: struct signature *uid_signatures; ! 91: char *uid_userid; ! 92: byte uid_legit; ! 93: }; ! 94: ! 95: struct signature { ! 96: struct signature *sig_next; /* list of signatures on a userid */ ! 97: struct userid *sig_uid; /* the userid it signs */ ! 98: struct pubkey *sig_from; /* key that made this signature */ ! 99: /* list of sigs made by the same key (sig_from) */ ! 100: struct signature *sig_nextfrom; ! 101: byte sig_trust; ! 102: }; ! 103: ! 104: ! 105: int maint_list(char *ringfile); ! 106: void init_trust_lst(void); ! 107: long lookup_by_keyID(FILE * f, byte * srch_keyID); ! 108: void show_userid(FILE * f, byte * keyID); ! 109: ! 110: static int maintenance(char *ringfile, struct newkey const *nkeys); ! 111: static int maint_read_data(char *ringfile, struct newkey const *nkeys); ! 112: static int maint_trace_chain(void); ! 113: static int trace_sig_chain(struct pubkey *pk, int depth); ! 114: static int maint_final(char *ringfile); ! 115: static struct pubkey *getpubkey(byte * keyID); ! 116: static void setup_trust(void); ! 117: static int check_secretkey(FILE * f, long keypos, byte keyctrl); ! 118: static void maint_init_mem(void); ! 119: static void maint_release_mem(void); ! 120: static VOID *allocn(int size); ! 121: static char *store_str(char *str); ! 122: static VOID *allocbuf(int size); ! 123: static void freebufpool(void); ! 124: static void compute_legit(struct userid *id); ! 125: ! 126: ! 127: #define ALLOC_UNIT 4000 /* memory will be allocated in chunks of this size */ ! 128: ! 129: #define MAX_DEPTH 8 /* max. value of max_cert_depth */ ! 130: ! 131: /* returned when trying to do a maintenance pass on a ! 132: secret keyring or keyfile */ ! 133: #define ERR_NOTRUST -7 ! 134: ! 135: #define TRUST_MASK 7 /* mask for userid/signature trust bytes */ ! 136: #define SET_TRUST(b,v) (*(b) = (*(b) & ~TRUST_MASK) | (v)) ! 137: #define TRUST_LEV(b) ((b) & TRUST_MASK) ! 138: ! 139: #define TRUST_FAC(x) (trust_tbl[TRUST_LEV(x)]) ! 140: ! 141: #define ctb_type(c) ((c&CTB_TYPE_MASK)>>2) ! 142: /* ! 143: * table for tuning user paranoia index. ! 144: * values represent contribution of one signature indexed by the ! 145: * SIGTRUST of a signature ! 146: */ ! 147: static int trust_tbl[8]; ! 148: ! 149: static int marginal_min; ! 150: static int complete_min; /* total count needed for a fully legit key */ ! 151: ! 152: int marg_min = 2; /* number of marginally trusted signatures ! 153: needed for a fully legit key ! 154: (can be set in config.pgp). */ ! 155: int compl_min = 1; /* number of fully trusted signatures needed */ ! 156: ! 157: char trust_lst[8][16] = ! 158: { ! 159: "undefined", /* LANG("undefined") */ ! 160: "unknown", /* LANG("unknown") */ ! 161: "untrusted", /* LANG("untrusted") */ ! 162: "<3>", /* unused */ ! 163: "<4>", /* unused */ ! 164: "marginal", /* LANG("marginal") */ ! 165: "complete", /* LANG("complete") */ ! 166: "ultimate", /* LANG("ultimate") */ ! 167: }; ! 168: ! 169: char legit_lst[4][16] = ! 170: { ! 171: "undefined", ! 172: "untrusted", ! 173: "marginal", ! 174: "complete" ! 175: }; ! 176: ! 177: static int trustlst_len = 9; /* length of longest trust word */ ! 178: static int legitlst_len = 9; /* length of longest legit word */ ! 179: ! 180: char floppyring[MAX_PATH] = ""; ! 181: int max_cert_depth = 4; /* maximum nesting of signatures */ ! 182: ! 183: static boolean check_only = FALSE; ! 184: static boolean mverbose; ! 185: static FILE *sec_fp; ! 186: static FILE *floppy_fp = NULL; ! 187: static int undefined_trust; /* number of complete keys with undef. trust */ ! 188: ! 189: /* ! 190: * Update trust parameters in a keyring, should be called after all ! 191: * key management functions which can affect the trust parameters. ! 192: * Changes are done "inplace", the file must be writable. ! 193: * ! 194: * nkeys is a list of new keys. Any key on this list is checked to ! 195: * see if it on the secret keyring. If it is, and the BUCKSTOP bit ! 196: * is not set, the user is prompted to set it. ! 197: */ ! 198: int maint_update(char *ringfile, struct newkey const *nkeys) ! 199: { ! 200: check_only = mverbose = FALSE; ! 201: return maintenance(ringfile, nkeys); ! 202: } ! 203: ! 204: /* ! 205: * Check trust parameters in ringfile ! 206: * options can be: ! 207: * MAINT_CHECK check only, don't ask if keyring should be updated ! 208: * MAINT_VERBOSE verbose output, shows signature chains ! 209: */ ! 210: int maint_check(char *ringfile, int options) ! 211: { ! 212: int status; ! 213: char *fixfile; ! 214: ! 215: mverbose = ((options & MAINT_VERBOSE) != 0); ! 216: ! 217: if (moreflag) ! 218: open_more(); ! 219: if (*floppyring != '\0' && (floppy_fp = fopen(floppyring, FOPRBIN)) ! 220: == NULL) ! 221: fprintf(pgpout, LANG("\nCan't open backup key ring file '%s'\n"), ! 222: floppyring); ! 223: check_only = TRUE; ! 224: status = maintenance(ringfile, NULL); ! 225: if (floppy_fp) { ! 226: fclose(floppy_fp); ! 227: floppy_fp = NULL; ! 228: } ! 229: if (status <= 0) { ! 230: if (status == 0) ! 231: maint_list(ringfile); ! 232: close_more(); ! 233: return status; ! 234: } ! 235: #ifdef xDEBUG ! 236: if (status > 0 && (options & MAINT_CHECK)) { ! 237: FILE *sav = pgpout; ! 238: if (pgpout = fopen("before.lst", "w")) { ! 239: maint_list(ringfile); ! 240: fclose(pgpout); ! 241: } ! 242: pgpout = sav; ! 243: } ! 244: #endif ! 245: /* Inform user of trust parameters to be changed... */ ! 246: if (undefined_trust) { ! 247: ! 248: /* If we are just going to check, then exit now... */ ! 249: if (options & MAINT_CHECK) { ! 250: maint_list(ringfile); ! 251: } ! 252: fprintf(pgpout, ! 253: LANG("\n%d \"trust parameter(s)\" need to be changed.\n"), ! 254: undefined_trust); ! 255: ! 256: if (options & MAINT_CHECK) { ! 257: close_more(); ! 258: return status; ! 259: } ! 260: fprintf(pgpout, LANG("Continue with '%s' (Y/n)? "), ! 261: ringfile); ! 262: if (!getyesno('y')) { ! 263: close_more(); ! 264: return status; ! 265: } ! 266: } ! 267: /* do the fixes in a scratch file */ ! 268: fixfile = tempfile(0); ! 269: if (copyfiles_by_name(ringfile, fixfile) < 0) { ! 270: close_more(); ! 271: return -1; ! 272: } ! 273: check_only = mverbose = FALSE; ! 274: if ((status = maintenance(fixfile, NULL)) >= 0) { ! 275: maint_list(fixfile); ! 276: fprintf(pgpout, ! 277: LANG("\n%d \"trust parameter(s)\" changed.\n"), status); ! 278: } ! 279: close_more(); ! 280: if (status > 0 && !(options & MAINT_CHECK)) { ! 281: fprintf(pgpout, LANG("Update public keyring '%s' (Y/n)? "), ringfile); ! 282: if (getyesno('y')) ! 283: return savetempbak(fixfile, ringfile); ! 284: } ! 285: rmtemp(fixfile); ! 286: return status; ! 287: } /* maint_check */ ! 288: ! 289: ! 290: static int maintenance(char *ringfile, struct newkey const *nkeys) ! 291: { ! 292: int status; ! 293: undefined_trust = 0; /* None so far... */ ! 294: ! 295: if (max_cert_depth > MAX_DEPTH) ! 296: max_cert_depth = MAX_DEPTH; ! 297: if ((sec_fp = fopen(globalSecringName, FOPRBIN)) == NULL) ! 298: fprintf(pgpout, LANG("\nCan't open secret key ring file '%s'\n"), ! 299: globalSecringName); ! 300: ! 301: setkrent(ringfile); ! 302: setup_trust(); ! 303: maint_init_mem(); ! 304: if (mverbose || verbose) ! 305: fprintf(pgpout, ! 306: LANG("\nPass 1: Looking for the \"ultimately-trusted\" keys...\n")); ! 307: status = maint_read_data(ringfile, nkeys); ! 308: if (sec_fp) { ! 309: fclose(sec_fp); ! 310: sec_fp = NULL; ! 311: } ! 312: if (status < 0) ! 313: goto failed; ! 314: ! 315: if (mverbose || verbose) ! 316: fprintf(pgpout, LANG("\nPass 2: Tracing signature chains...\n")); ! 317: if ((status = maint_trace_chain()) < 0) ! 318: goto failed; ! 319: ! 320: if (verbose) ! 321: fprintf(pgpout, "\nPass 3: %s keyring...\n", ! 322: (check_only ? "Checking with" : "Updating")); ! 323: if ((status = maint_final(ringfile)) < 0) ! 324: goto failed; ! 325: ! 326: endkrent(); ! 327: maint_release_mem(); ! 328: return status + undefined_trust; ! 329: ! 330: failed: ! 331: if (verbose) ! 332: fprintf(pgpout, "maintenance pass: error exit = %d\n", status); ! 333: endkrent(); ! 334: maint_release_mem(); ! 335: return status; ! 336: } /* maintenance */ ! 337: ! 338: ! 339: static struct pubkey *pklist, **pkhash = NULL; ! 340: ! 341: #define PK_HASHSIZE 256 /* must be power of 2 */ ! 342: #define PK_HASH(x) (*(byte *) (x) & (PK_HASHSIZE - 1)) ! 343: ! 344: /* ! 345: * get the pubkey struct for keyID from hash table, allocate a new ! 346: * node and insert in hash table if necessary. ! 347: */ ! 348: static struct pubkey * ! 349: getpubkey(byte * keyID) ! 350: { ! 351: struct pubkey *pk; ! 352: for (pk = pkhash[PK_HASH(keyID)]; pk; pk = pk->pk_hash) ! 353: if (memcmp(pk->pk_keyid, keyID, KEYFRAGSIZE) == 0) ! 354: return pk; ! 355: pk = allocn(sizeof(struct pubkey)); ! 356: memset(pk, 0, sizeof(struct pubkey)); ! 357: memcpy(pk->pk_keyid, keyID, KEYFRAGSIZE); ! 358: pk->pk_hash = pkhash[PK_HASH(keyID)]; ! 359: pkhash[PK_HASH(keyID)] = pk; ! 360: return pk; ! 361: } ! 362: ! 363: /* ! 364: * Read in keyring, a graph of keys, userids and signatures is built. ! 365: * Also check if axiomatic keys are present in the secret keyring and ! 366: * compare them with the floppy ring if this is requested. ! 367: */ ! 368: static int maint_read_data(char *ringfile, struct newkey const *nkeys) ! 369: { ! 370: FILE *f; ! 371: int status; ! 372: char userid[256]; ! 373: byte keyID[KEYFRAGSIZE]; ! 374: byte sigkeyID[KEYFRAGSIZE]; ! 375: byte ctb; ! 376: byte keyctrl; ! 377: boolean buckstop = FALSE, show_user = FALSE; ! 378: int buckstopcount = 0; ! 379: long keypos = 0; ! 380: int skip = 0; ! 381: struct pubkey *pk = NULL; ! 382: struct userid *id = NULL; ! 383: struct signature *sig = NULL; ! 384: ! 385: if ((f = fopen(ringfile, FOPRBIN)) == NULL) { ! 386: fprintf(pgpout, ! 387: LANG("\n\007Can't open key ring file '%s'\n"), ringfile); ! 388: return -1; ! 389: } ! 390: while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) { ! 391: if (status == -3 || status == -2) { ! 392: fclose(f); ! 393: return status; ! 394: } ! 395: if (status < 0 || is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) { ! 396: skip = 1; /* version error or bad key */ ! 397: continue; ! 398: } ! 399: if (skip) { ! 400: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) ! 401: skip = 0; ! 402: else ! 403: continue; ! 404: } ! 405: if (is_ctb_type(ctb, CTB_COMMENT_TYPE) || ctb == CTB_KEYCTRL) ! 406: continue; ! 407: ! 408: if (pk && is_ctb_type(ctb, CTB_SKE_TYPE) && !pk->pk_userids) { ! 409: /* sig. cert before userids can only be compromise cert. */ ! 410: pk->pk_owntrust = KC_OWNERTRUST_NEVER; ! 411: continue; ! 412: } ! 413: /* other packets should have trust byte */ ! 414: if (read_trust(f, &keyctrl) < 0) { ! 415: fclose(f); ! 416: return ERR_NOTRUST; /* not a public keyring */ ! 417: } ! 418: switch (ctb_type(ctb)) { ! 419: case CTB_CERT_PUBKEY_TYPE: ! 420: if (pk) ! 421: pk = pk->pk_next = getpubkey(keyID); ! 422: else ! 423: pk = pklist = getpubkey(keyID); ! 424: ! 425: if (pk->pk_next) { ! 426: fprintf(pgpout, ! 427: LANG("Keyring contains duplicate key: %s\n"), ! 428: keyIDstring(keyID)); ! 429: fclose(f); ! 430: return -1; ! 431: } ! 432: if (keyctrl & KC_BUCKSTOP || ! 433: ismember_newkeys(keyID, nkeys)) { ! 434: if (check_secretkey(f, keypos, keyctrl) == 0) { ! 435: ++buckstopcount; ! 436: keyctrl |= KC_BUCKSTOP; ! 437: SET_TRUST(&keyctrl, KC_OWNERTRUST_ULTIMATE); ! 438: buckstop = TRUE; ! 439: if (mverbose) ! 440: fprintf(pgpout, "* %s", keyIDstring(keyID)); ! 441: } else { /* not in secret keyring */ ! 442: keyctrl &= ~KC_BUCKSTOP; ! 443: if (TRUST_LEV(keyctrl) == KC_OWNERTRUST_ULTIMATE) ! 444: keyctrl = KC_OWNERTRUST_ALWAYS; ! 445: if (mverbose) ! 446: fprintf(pgpout, ". %s", keyIDstring(keyID)); ! 447: } ! 448: show_user = mverbose; ! 449: } else { ! 450: buckstop = FALSE; ! 451: show_user = FALSE; ! 452: } ! 453: pk->pk_owntrust = keyctrl; ! 454: pk->pk_userids = id = NULL; ! 455: break; ! 456: case CTB_USERID_TYPE: ! 457: #ifdef MACTC5 ! 458: mac_poll_for_break(); ! 459: #endif ! 460: if (!pk) ! 461: break; ! 462: if (show_user) { ! 463: if (pk->pk_userids) /* more than one user ID */ ! 464: fprintf(pgpout, " "); ! 465: fprintf(pgpout, " %s\n", LOCAL_CHARSET(userid)); ! 466: } ! 467: if (id) ! 468: id = id->uid_next = allocn(sizeof(struct userid)); ! 469: else ! 470: id = pk->pk_userids = allocn(sizeof(struct userid)); ! 471: ! 472: if (mverbose) ! 473: id->uid_userid = store_str(userid); ! 474: keyctrl &= ~KC_LEGIT_MASK; ! 475: if (buckstop) ! 476: keyctrl |= KC_LEGIT_COMPLETE; ! 477: else ! 478: keyctrl |= KC_LEGIT_UNKNOWN; ! 479: id->uid_next = NULL; ! 480: id->uid_key = pk; ! 481: id->uid_legit = keyctrl; ! 482: id->uid_signatures = sig = NULL; ! 483: break; ! 484: case CTB_SKE_TYPE: ! 485: if (!pk || !id) ! 486: break; ! 487: if (sig) ! 488: sig = sig->sig_next = allocn(sizeof(struct signature)); ! 489: else ! 490: sig = id->uid_signatures = allocn(sizeof(struct signature)); ! 491: sig->sig_next = NULL; ! 492: sig->sig_uid = id; ! 493: sig->sig_from = getpubkey(sigkeyID); ! 494: sig->sig_nextfrom = sig->sig_from->pk_signed; ! 495: sig->sig_from->pk_signed = sig; ! 496: sig->sig_trust = keyctrl & KC_SIG_CHECKED; ! 497: break; ! 498: } /* switch ctb_type */ ! 499: keypos = ftell(f); ! 500: } ! 501: if (buckstopcount == 0 && mverbose) ! 502: fprintf(pgpout, LANG("No ultimately-trusted keys.\n")); ! 503: fclose(f); ! 504: return 0; ! 505: } /* maint_read_data */ ! 506: ! 507: /* ! 508: * scan keyring for buckstop keys and start the recursive trace_sig_chain() ! 509: * on them ! 510: */ ! 511: static int maint_trace_chain(void) ! 512: { ! 513: char *userid; ! 514: struct pubkey *pk; ! 515: ! 516: for (pk = pklist; pk; pk = pk->pk_next) { ! 517: if (!(pk->pk_owntrust & KC_BUCKSTOP)) ! 518: continue; ! 519: if (mverbose) ! 520: fprintf(pgpout, ! 521: "* %s\n", LOCAL_CHARSET(pk->pk_userids->uid_userid)); ! 522: if (TRUST_LEV(pk->pk_owntrust) == KC_OWNERTRUST_UNDEFINED) { ! 523: userid = user_from_keyID(pk->pk_keyid); ! 524: SET_TRUST(&pk->pk_owntrust, ask_owntrust(userid, pk->pk_owntrust)); ! 525: } ! 526: trace_sig_chain(pk, 0); ! 527: } ! 528: return 0; ! 529: } /* maint_trace_chain */ ! 530: ! 531: ! 532: /* ! 533: * Find all signatures made with the key pk. ! 534: * If a trusted signature makes a key fully legit then signatures made ! 535: * with this key are also recursively traced on down the tree. ! 536: * ! 537: * depth is the level of recursion, it is used to indent the userIDs ! 538: * and to check if we don't exceed the limit "max_cert_depth" ! 539: * ! 540: * NOTE: a signature made with a key with pk_depth == max_cert_depth will ! 541: * not be counted here to limit the maximum chain length, but will be ! 542: * counted when the validity of a key is computed in maint_final() ! 543: */ ! 544: static int trace_sig_chain(struct pubkey *pk, int depth) ! 545: { ! 546: int d, trust_count = 0; ! 547: int counts[MAX_DEPTH]; ! 548: struct signature *sig, *s; ! 549: struct pubkey *p; ! 550: struct userid *id; ! 551: ! 552: assert(depth <= max_cert_depth); ! 553: if (pk->pk_depth && pk->pk_depth <= depth) ! 554: return 0; ! 555: pk->pk_depth = depth; ! 556: ! 557: /* Should we ask for trust. If this key is legit, then go for ! 558: * it! Ask the user.... ! 559: */ ! 560: if (TRUST_LEV(pk->pk_owntrust) == KC_OWNERTRUST_UNDEFINED) ! 561: for (id = pk->pk_userids; id; id = id->uid_next) { ! 562: compute_legit(id); ! 563: if ((id->uid_legit & KC_LEGIT_MASK) == ! 564: KC_LEGIT_COMPLETE) { ! 565: SET_TRUST(&pk->pk_owntrust, ! 566: ask_owntrust(user_from_keyID(pk->pk_keyid), ! 567: pk->pk_owntrust)); ! 568: break; ! 569: } ! 570: } ! 571: /* Return if I haven't signed anyone's keys, since I ! 572: * don't need to check any further.. -warlord 93-04-11 ! 573: */ ! 574: if (!pk->pk_signed) ! 575: return 0; ! 576: ! 577: #ifdef DEBUG ! 578: if (mverbose) ! 579: fprintf(pgpout, "%*s%d-v %s\n", 2 * depth, "", ! 580: depth, pk->pk_userids->uid_userid); ! 581: #endif ! 582: ! 583: /* all keys signed by pk */ ! 584: for (sig = pk->pk_signed; sig; sig = sig->sig_nextfrom) { ! 585: ! 586: /* If signature is good, copy trust from signator */ ! 587: /* CONTIG bit currently unused */ ! 588: if (sig->sig_trust & KC_SIG_CHECKED) { ! 589: SET_TRUST(&sig->sig_trust, TRUST_LEV(pk->pk_owntrust)); ! 590: sig->sig_trust |= KC_CONTIG; /* CONTIG bit currently unused */ ! 591: if (mverbose) ! 592: fprintf(pgpout, "%*s > %s\n", 2 * depth, "", ! 593: LOCAL_CHARSET(sig->sig_uid->uid_userid)); ! 594: } else { ! 595: SET_TRUST(&sig->sig_trust, KC_SIGTRUST_UNTRUSTED); ! 596: sig->sig_trust &= ~KC_CONTIG; ! 597: if (mverbose) ! 598: fprintf(pgpout, "%*s X %s\n", 2 * depth, "", ! 599: LOCAL_CHARSET(sig->sig_uid->uid_userid)); ! 600: } ! 601: ! 602: if (TRUST_FAC(sig->sig_trust) == 0) ! 603: continue; ! 604: p = sig->sig_uid->uid_key; /* this key signed by pk */ ! 605: if (p->pk_owntrust & KC_BUCKSTOP) ! 606: continue; /* will be handled from main loop */ ! 607: if (p->pk_depth && p->pk_depth <= depth + 1) ! 608: continue; /* already handled this key at a lower level */ ! 609: ! 610: for (d = 0; d < max_cert_depth; ++d) ! 611: counts[d] = 0; ! 612: for (s = sig->sig_uid->uid_signatures; s; s = s->sig_next) { ! 613: d = s->sig_from->pk_depth; ! 614: if (d < max_cert_depth) ! 615: counts[d] += TRUST_FAC(s->sig_trust); ! 616: } ! 617: /* ! 618: * find a combination of signatures that will make the key ! 619: * valid through the shortest cert. path. ! 620: */ ! 621: trust_count = 0; ! 622: for (d = 0; d < max_cert_depth; ++d) { ! 623: trust_count += counts[d]; ! 624: if (trust_count >= complete_min) { ! 625: trace_sig_chain(p, d + 1); ! 626: break; ! 627: } ! 628: } ! 629: } ! 630: ! 631: #ifdef DEBUG ! 632: if (mverbose) ! 633: fprintf(pgpout, "%*s%d-^ %s\n", 2 * depth, "", ! 634: depth, pk->pk_userids->uid_userid); ! 635: #endif ! 636: return 0; ! 637: } /* trace_sig_chain */ ! 638: ! 639: /* ! 640: * compute validity of userid/key pair, the number of signatures and the ! 641: * trust level of these signatures determines the validity. ! 642: */ ! 643: static void compute_legit(struct userid *id) ! 644: { ! 645: struct signature *s; ! 646: int trust_count, legit; ! 647: ! 648: if (id->uid_key->pk_owntrust & KC_BUCKSTOP) ! 649: legit = KC_LEGIT_COMPLETE; ! 650: else { ! 651: trust_count = 0; ! 652: for (s = id->uid_signatures; s; s = s->sig_next) ! 653: trust_count += TRUST_FAC(s->sig_trust); ! 654: ! 655: if (trust_count == 0) ! 656: legit = KC_LEGIT_UNKNOWN; ! 657: else if (trust_count < marginal_min) ! 658: legit = KC_LEGIT_UNTRUSTED; ! 659: else if (trust_count < complete_min) ! 660: legit = KC_LEGIT_MARGINAL; ! 661: else ! 662: legit = KC_LEGIT_COMPLETE; ! 663: } ! 664: id->uid_legit = (id->uid_legit & ~KC_LEGIT_MASK) | legit; ! 665: } /* compute_legit */ ! 666: ! 667: /* ! 668: * check if the maintenance pass changed anything ! 669: * returns 0 if files f and g are equal and the number of changed ! 670: * trust bytes if the files are different or a negative value on error ! 671: */ ! 672: static int maint_final(char *ringfile) ! 673: { ! 674: int status; ! 675: FILE *f; ! 676: long trust_pos = 0; ! 677: char userid[256]; ! 678: byte keyID[KEYFRAGSIZE]; ! 679: byte sigkeyID[KEYFRAGSIZE]; ! 680: byte ctb; ! 681: byte kc_orig, kc_new = 0, mask; ! 682: int changed = 0; ! 683: int skip = 0; ! 684: struct pubkey *pk; ! 685: struct userid *id = NULL; ! 686: struct signature *sig = NULL; ! 687: ! 688: if (check_only) ! 689: f = fopen(ringfile, FOPRBIN); ! 690: else ! 691: f = fopen(ringfile, FOPRWBIN); ! 692: if (f == NULL) { ! 693: fprintf(pgpout, ! 694: LANG("\n\007Can't open key ring file '%s'\n"), ringfile); ! 695: return -1; ! 696: } ! 697: pk = pklist; ! 698: while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) { ! 699: if (status == -3 || status == -2) ! 700: break; ! 701: if (status < 0 || is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) { ! 702: skip = 1; ! 703: continue; ! 704: } ! 705: if (skip) { ! 706: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) ! 707: skip = 0; ! 708: else ! 709: continue; ! 710: } ! 711: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE) || ! 712: is_ctb_type(ctb, CTB_SKE_TYPE) || ctb == CTB_USERID) { ! 713: trust_pos = ftell(f); ! 714: if (read_trust(f, &kc_orig) < 0) { ! 715: status = ERR_NOTRUST; ! 716: if (is_ctb_type(ctb, CTB_SKE_TYPE)) ! 717: continue; /* skip compr. cert. */ ! 718: else ! 719: break; ! 720: } ! 721: } ! 722: switch (ctb_type(ctb)) { ! 723: case CTB_CERT_PUBKEY_TYPE: ! 724: assert(pk && !memcmp(pk->pk_keyid, keyID, KEYFRAGSIZE)); ! 725: assert(!sig && !id); ! 726: id = pk->pk_userids; ! 727: kc_new = pk->pk_owntrust; ! 728: #ifdef DEBUG ! 729: if (mverbose) ! 730: fprintf(pgpout, " ------ %d\n", pk->pk_depth); ! 731: #endif ! 732: pk = pk->pk_next; ! 733: mask = KC_OWNERTRUST_MASK | KC_BUCKSTOP; ! 734: break; ! 735: case CTB_USERID_TYPE: ! 736: assert(id && !sig); ! 737: #ifdef MACTC5 ! 738: mac_poll_for_break(); ! 739: #endif ! 740: sig = id->uid_signatures; ! 741: compute_legit(id); ! 742: kc_new = id->uid_legit; ! 743: #ifdef DEBUG ! 744: if (mverbose) ! 745: fprintf(pgpout, "%c %02x %02x %s\n", ! 746: ' ' + (kc_new != kc_orig), ! 747: kc_orig, kc_new, id->uid_userid); ! 748: #endif ! 749: id = id->uid_next; ! 750: mask = KC_LEGIT_MASK; ! 751: break; ! 752: case CTB_SKE_TYPE: ! 753: assert(sig); ! 754: assert(!memcmp(sig->sig_from->pk_keyid, sigkeyID, KEYFRAGSIZE)); ! 755: kc_new = sig->sig_trust; ! 756: #ifdef DEBUG ! 757: if (mverbose && sig->sig_from->pk_userids) ! 758: fprintf(pgpout, "%c %02x %02x %s\n", ! 759: ' ' + (kc_new != kc_orig), ! 760: kc_orig, kc_new, sig->sig_from->pk_userids->uid_userid); ! 761: #endif ! 762: sig = sig->sig_next; ! 763: mask = KC_SIGTRUST_MASK | KC_CONTIG; ! 764: break; ! 765: default: ! 766: mask = 0; ! 767: } ! 768: if ((kc_new & mask) != (kc_orig & mask)) { ! 769: if (!check_only) ! 770: write_trust_pos(f, kc_new, trust_pos); ! 771: ++changed; ! 772: } ! 773: } ! 774: fclose(f); ! 775: if (status < -1) /* -1 is OK, EOF */ ! 776: return status; ! 777: if (pk || sig || id) { ! 778: fprintf(pgpout, "maint_final: internal error\n"); ! 779: return -1; ! 780: } ! 781: return changed; ! 782: } /* maint_final */ ! 783: ! 784: int maint_list(char *ringfile) ! 785: { ! 786: int status; ! 787: FILE *f; ! 788: char userid[256]; ! 789: byte keyID[KEYFRAGSIZE]; ! 790: byte sigkeyID[KEYFRAGSIZE]; ! 791: char *signator; ! 792: char tchar = 0; ! 793: byte ctb, kc; ! 794: int owntrust = 0; ! 795: int usercount = 0; ! 796: ! 797: if ((f = fopen(ringfile, FOPRBIN)) == NULL) { ! 798: fprintf(pgpout, ! 799: LANG("\n\007Can't open key ring file '%s'\n"), ringfile); ! 800: return -1; ! 801: } ! 802: init_trust_lst(); ! 803: setkrent(ringfile); ! 804: init_userhash(); ! 805: ! 806: fprintf(pgpout, LANG(" KeyID Trust Validity User ID\n")); ! 807: while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) { ! 808: if (status == -3 || status == -2) ! 809: break; ! 810: if (status < 0) ! 811: continue; ! 812: ! 813: if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE) || ! 814: is_ctb_type(ctb, CTB_SKE_TYPE) || ctb == CTB_USERID) { ! 815: if (read_trust(f, &kc) < 0) { ! 816: status = ERR_NOTRUST; ! 817: /* compromise cert. don't have trust byte */ ! 818: if (!is_ctb_type(ctb, CTB_SKE_TYPE)) ! 819: break; ! 820: } ! 821: } ! 822: #ifdef MACTC5 ! 823: { ! 824: extern int BreakCntl; ! 825: if (!BreakCntl) BreakCntl = 35; ! 826: mac_poll_for_break(); ! 827: } ! 828: #endif ! 829: ! 830: switch (ctb_type(ctb)) { ! 831: case CTB_CERT_PUBKEY_TYPE: ! 832: tchar = (kc & KC_BUCKSTOP ? '*' : ' '); ! 833: owntrust = TRUST_LEV(kc); ! 834: usercount = 0; ! 835: userid[0] = '\0'; ! 836: break; ! 837: case CTB_USERID_TYPE: ! 838: if (!usercount) { /* first userid */ ! 839: fprintf(pgpout, "%c %s ", tchar, keyIDstring(keyID)); ! 840: fprintf(pgpout, "%-*s ", trustlst_len, trust_lst[owntrust]); ! 841: } else ! 842: fprintf(pgpout, " %s %*s ", blankkeyID, trustlst_len, ""); ! 843: fprintf(pgpout, "%-*s ", legitlst_len, ! 844: legit_lst[kc & KC_LEGIT_MASK]); ! 845: if (usercount) ! 846: putc(' ', pgpout); ! 847: ++usercount; ! 848: fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid)); ! 849: break; ! 850: case CTB_SKE_TYPE: ! 851: if (!usercount) { /* sig before userid: compromise cert. */ ! 852: tchar = '#'; ! 853: break; ! 854: } ! 855: fprintf(pgpout, "%c %s ", ! 856: (kc & KC_CONTIG) ? 'c' : ' ', blankkeyID); ! 857: fprintf(pgpout, "%-*s ", trustlst_len, trust_lst[TRUST_LEV(kc)]); ! 858: fprintf(pgpout, "%*s ", legitlst_len, ""); ! 859: if ((signator = user_from_keyID(sigkeyID)) == NULL) ! 860: fprintf(pgpout, LANG("(KeyID: %s)\n"), keyIDstring(sigkeyID)); ! 861: else ! 862: fprintf(pgpout, "%s\n", LOCAL_CHARSET(signator)); ! 863: break; ! 864: } ! 865: } ! 866: endkrent(); ! 867: fclose(f); ! 868: if (status < -1) /* -1 is OK, EOF */ ! 869: return status; ! 870: return 0; ! 871: } /* maint_list */ ! 872: ! 873: /* ! 874: * translate the messages in the arrays trust_lst and legit_lst. ! 875: * trustlst_len and legitlst_len will be set to the length of ! 876: * the longest translated string. ! 877: */ ! 878: void init_trust_lst(void) ! 879: { ! 880: static int initialized = 0; ! 881: int i, len; ! 882: char *s; ! 883: ! 884: if (initialized) ! 885: return; ! 886: for (i = 0; i < 8; ++i) { ! 887: if (trust_lst[i][0]) { ! 888: s = LANG(trust_lst[i]); ! 889: if (s != trust_lst[i]) ! 890: strncpy(trust_lst[i], s, sizeof(trust_lst[0]) - 1); ! 891: len = strlen(s); ! 892: if (len > trustlst_len) ! 893: trustlst_len = len; ! 894: } ! 895: } ! 896: for (i = 0; i < 4; ++i) { ! 897: s = LANG(legit_lst[i]); ! 898: if (s != legit_lst[i]) ! 899: strncpy(legit_lst[i], s, sizeof(legit_lst[0]) - 1); ! 900: len = strlen(s); ! 901: if (len > legitlst_len) ! 902: legitlst_len = len; ! 903: } ! 904: initialized = 1; ! 905: } /* init_trust_lst */ ! 906: ! 907: ! 908: ! 909: /* ! 910: * compare the key in file f at keypos with the matching key in the ! 911: * secret keyring, the global variable sec_fp must contain the file pointer ! 912: * for of the secret keyring. ! 913: * ! 914: * returns 1 if the key was not found, -2 if the keys were different ! 915: * and 0 if the keys compared OK ! 916: */ ! 917: static int check_secretkey(FILE * f, long keypos, byte keyctrl) ! 918: { ! 919: int status = -1; ! 920: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 921: unit nsec[MAX_UNIT_PRECISION], esec[MAX_UNIT_PRECISION]; ! 922: char userid[256]; ! 923: byte keyID[KEYFRAGSIZE]; ! 924: long savepos, pktlen; ! 925: byte ctb; ! 926: ! 927: if (sec_fp == NULL) ! 928: return -1; ! 929: ! 930: savepos = ftell(f); ! 931: fseek(f, keypos, SEEK_SET); ! 932: if (readkeypacket(f, FALSE, &ctb, NULL, NULL, n, e, ! 933: NULL, NULL, NULL, NULL, NULL, NULL) < 0) ! 934: goto ex; ! 935: extract_keyID(keyID, n); ! 936: ! 937: do { /* get userid */ ! 938: status = readkpacket(f, &ctb, userid, NULL, NULL); ! 939: if (status == -1 || status == -3) ! 940: goto ex; ! 941: } while (ctb != CTB_USERID); ! 942: ! 943: if (lookup_by_keyID(sec_fp, keyID) < 0) { ! 944: #if 0 ! 945: if (!check_only) { ! 946: fprintf(pgpout, ! 947: LANG("\nAn \"axiomatic\" key is one which does not need certifying by\n\ ! 948: anyone else. Usually this special status is reserved only for your\n\ ! 949: own keys, which should also appear on your secret keyring. The owner\n\ ! 950: of an axiomatic key (who is typically yourself) is \"ultimately trusted\"\n\ ! 951: by you to certify any or all other keys.\n")); ! 952: fprintf(pgpout, LANG("\nKey for user ID \"%s\"\n\ ! 953: is designated as an \"ultimately-trusted\" introducer, but the key\n\ ! 954: does not appear in the secret keyring.\n\ ! 955: Use this key as an ultimately-trusted introducer (y/N)? "), ! 956: LOCAL_CHARSET(userid)); ! 957: status = (getyesno('n') ? 0 : 1); ! 958: } ! 959: #else ! 960: status = 1; ! 961: #endif ! 962: } else { ! 963: long kpos = ftell(sec_fp); ! 964: if (readkeypacket(sec_fp, FALSE, &ctb, NULL, NULL, nsec, esec, ! 965: NULL, NULL, NULL, NULL, NULL, NULL) < 0) { ! 966: fprintf(pgpout, LANG("\n\007Cannot read from secret keyring.\n")); ! 967: status = -3; ! 968: goto ex; ! 969: } ! 970: if (mp_compare(n, nsec) || mp_compare(e, esec)) { ! 971: /* Red Alert! */ ! 972: fprintf(pgpout, ! 973: LANG("\n\007WARNING: Public key for user ID: \"%s\"\n\ ! 974: does not match the corresponding key in the secret keyring.\n"), ! 975: LOCAL_CHARSET(userid)); ! 976: fprintf(pgpout, ! 977: LANG("This is a serious condition, indicating possible keyring tampering.\n")); ! 978: status = -2; ! 979: } else { ! 980: status = 0; ! 981: } ! 982: ! 983: /* Okay, key is in secret key ring, and it matches. */ ! 984: if (!(keyctrl & KC_BUCKSTOP)) { ! 985: if (batchmode) { ! 986: status = -1; ! 987: } else { ! 988: fprintf(pgpout, LANG("\nKey for user ID \"%s\"\n\ ! 989: also appears in the secret key ring."), LOCAL_CHARSET(userid)); ! 990: fputs( ! 991: LANG("\nUse this key as an ultimately-trusted introducer (y/N)? "), ! 992: pgpout); ! 993: status = getyesno('n') ? 0 : -1; ! 994: } ! 995: } ! 996: if (status == 0 && floppy_fp) { ! 997: if (lookup_by_keyID(floppy_fp, keyID) < 0) { ! 998: fprintf(pgpout, LANG("Public key for: \"%s\"\n\ ! 999: is not present in the backup keyring '%s'.\n"), ! 1000: LOCAL_CHARSET(userid), floppyring); ! 1001: } else { ! 1002: pktlen = ftell(sec_fp) - kpos; ! 1003: fseek(sec_fp, kpos, SEEK_SET); ! 1004: while (--pktlen >= 0 && getc(sec_fp) == getc(floppy_fp)); ! 1005: if (pktlen != -1) { ! 1006: fprintf(pgpout, ! 1007: LANG("\n\007WARNING: Secret key for: \"%s\"\n\ ! 1008: does not match the key in the backup keyring '%s'.\n"), ! 1009: LOCAL_CHARSET(userid), floppyring); ! 1010: fprintf(pgpout, ! 1011: LANG("This is a serious condition, indicating possible keyring tampering.\n")); ! 1012: status = -2; ! 1013: } ! 1014: } ! 1015: } ! 1016: } ! 1017: ex: ! 1018: fseek(f, savepos, SEEK_SET); ! 1019: return status; ! 1020: } /* check_secretkey */ ! 1021: ! 1022: /* ! 1023: * setup tables for trust scoring. ! 1024: */ ! 1025: static void setup_trust(void) ! 1026: { ! 1027: /* initialize trust table */ ! 1028: if (marg_min == 0) { /* marginally trusted signatures are ignored */ ! 1029: trust_tbl[5] = 0; ! 1030: trust_tbl[6] = 1; ! 1031: complete_min = compl_min; ! 1032: } else { ! 1033: if (marg_min < compl_min) ! 1034: marg_min = compl_min; ! 1035: trust_tbl[5] = compl_min; ! 1036: trust_tbl[6] = marg_min; ! 1037: complete_min = compl_min * marg_min; ! 1038: } ! 1039: trust_tbl[7] = complete_min; /* ultimate trust */ ! 1040: marginal_min = complete_min / 2; ! 1041: } /* setup_trust */ ! 1042: ! 1043: /* Ask for a wetware decision from the human on how much to trust ! 1044: this key's owner to certify other keys. Returns trust value. */ ! 1045: int ask_owntrust(char *userid, byte cur_trust) ! 1046: { ! 1047: char buf[8]; ! 1048: ! 1049: if (check_only || filter_mode || batchmode) { ! 1050: /* not interactive */ ! 1051: ++undefined_trust; /* We complete/undefined. Why? */ ! 1052: return KC_OWNERTRUST_UNDEFINED; ! 1053: } ! 1054: #ifdef MACTC5 ! 1055: get_trust(buf,userid); ! 1056: #endif ! 1057: fprintf(pgpout, ! 1058: LANG("\nMake a determination in your own mind whether this key actually\n\ ! 1059: belongs to the person whom you think it belongs to, based on available\n\ ! 1060: evidence. If you think it does, then based on your estimate of\n\ ! 1061: that person's integrity and competence in key management, answer\n\ ! 1062: the following question:\n")); ! 1063: fprintf(pgpout, LANG("\nWould you trust \"%s\"\n\ ! 1064: to act as an introducer and certify other people's public keys to you?\n\ ! 1065: (1=I don't know. 2=No. 3=Usually. 4=Yes, always.) ? "), ! 1066: LOCAL_CHARSET(userid)); ! 1067: fflush(pgpout); ! 1068: #ifdef MACTC5 ! 1069: Putchar(buf[0]); ! 1070: Putchar('\n'); ! 1071: #else ! 1072: getstring(buf, sizeof(buf) - 1, TRUE); ! 1073: #endif ! 1074: switch (buf[0]) { ! 1075: case '1': ! 1076: return KC_OWNERTRUST_UNKNOWN; ! 1077: case '2': ! 1078: return KC_OWNERTRUST_NEVER; ! 1079: case '3': ! 1080: return KC_OWNERTRUST_USUALLY; ! 1081: case '4': ! 1082: return KC_OWNERTRUST_ALWAYS; ! 1083: default: ! 1084: return TRUST_LEV(cur_trust); ! 1085: } ! 1086: } /* ask_owntrust */ ! 1087: ! 1088: /* ! 1089: * scan keyfile f for keyID srch_keyID. ! 1090: * returns the file position of the key if it is found, and sets the ! 1091: * file pointer to the start of the key packet. ! 1092: * returns -1 if the key was not found or < -1 if there was an error ! 1093: */ ! 1094: long lookup_by_keyID(FILE * f, byte * srch_keyID) ! 1095: { ! 1096: int status; ! 1097: long keypos = 0; ! 1098: byte keyID[KEYFRAGSIZE]; ! 1099: byte ctb; ! 1100: ! 1101: rewind(f); ! 1102: while ((status = readkpacket(f, &ctb, NULL, keyID, NULL)) != -1) { ! 1103: if (status == -3 || status == -2) ! 1104: break; ! 1105: if (status < 0) ! 1106: continue; ! 1107: if (is_key_ctb(ctb) && memcmp(keyID, srch_keyID, KEYFRAGSIZE) == 0) { ! 1108: fseek(f, keypos, SEEK_SET); ! 1109: return keypos; ! 1110: } ! 1111: keypos = ftell(f); ! 1112: } ! 1113: return status; ! 1114: } /* lookup_by_keyID */ ! 1115: ! 1116: /* ! 1117: * look up the key matching "keyID" and print the first userID ! 1118: * of this key. File position of f is saved. ! 1119: */ ! 1120: void show_userid(FILE * f, byte * keyID) ! 1121: { ! 1122: int status; ! 1123: long filepos; ! 1124: char userid[256]; ! 1125: byte ctb; ! 1126: ! 1127: filepos = ftell(f); ! 1128: if (lookup_by_keyID(f, keyID) >= 0) ! 1129: while ((status = readkpacket(f, &ctb, userid, NULL, NULL)) != -1 ! 1130: && status != -3) ! 1131: if (ctb == CTB_USERID) { ! 1132: fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid)); ! 1133: fseek(f, filepos, SEEK_SET); ! 1134: return; ! 1135: } ! 1136: fprintf(pgpout, LANG("(KeyID: %s)\n"), keyIDstring(keyID)); ! 1137: fseek(f, filepos, SEEK_SET); ! 1138: } /* show_userid */ ! 1139: ! 1140: /* ! 1141: * messages printed by show_key() ! 1142: */ ! 1143: static char *owntrust_msg[] = ! 1144: { ! 1145: "", /* Just don't say anything in this case */ ! 1146: "", ! 1147: _LANG("This user is untrusted to certify other keys.\n"), ! 1148: "", /* reserved */ ! 1149: "", /* reserved */ ! 1150: _LANG("This user is generally trusted to certify other keys.\n"), ! 1151: _LANG("This user is completely trusted to certify other keys.\n"), ! 1152: _LANG("This axiomatic key is ultimately trusted to certify other keys.\n"), ! 1153: }; ! 1154: static char *keylegit_msg[] = ! 1155: { ! 1156: _LANG("This key/userID association is not certified.\n"), ! 1157: _LANG("This key/userID association is not certified.\n"), ! 1158: _LANG("This key/userID association is marginally certified.\n"), ! 1159: _LANG("This key/userID association is fully certified.\n"), ! 1160: }; ! 1161: static char *sigtrust_msg[] = ! 1162: { ! 1163: _LANG(" Questionable certification from:\n "), ! 1164: _LANG(" Questionable certification from:\n "), ! 1165: _LANG(" Untrusted certification from:\n "), ! 1166: "", /* reserved */ ! 1167: "", /* reserved */ ! 1168: _LANG(" Generally trusted certification from:\n "), ! 1169: _LANG(" Completely trusted certification from:\n "), ! 1170: _LANG(" Axiomatically trusted certification from:\n "), ! 1171: }; ! 1172: ! 1173: /* ! 1174: * show the key in file f at file position keypos. ! 1175: * 'what' controls the info that will be shown: ! 1176: * SHOW_TRUST: show trust byte info ! 1177: * SHOW_SIGS: show signatures ! 1178: * SHOW_HASH: show key fingerprint ! 1179: * these constants can be or'ed ! 1180: * ! 1181: * 'what' can also be SHOW_LISTFMT to get the same format as for pgp -kv ! 1182: * no signatures or extra userids will be printed in this case. ! 1183: * ! 1184: * 'what' can be SHOW_CHANGE, in which case it will take the keyID and ! 1185: * call show_update(); ! 1186: */ ! 1187: int show_key(FILE * f, long keypos, int what) ! 1188: { ! 1189: int status, keystatus = -1; ! 1190: long filepos; ! 1191: char userid[256]; ! 1192: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1193: byte sigkeyID[KEYFRAGSIZE]; ! 1194: word32 timestamp; ! 1195: byte ctb, keyctb = 0, keyctrl; ! 1196: int userids = 0; ! 1197: int keyids = 0; ! 1198: byte savekeyID[KEYFRAGSIZE]; ! 1199: boolean print_trust = FALSE; ! 1200: byte hash[16]; ! 1201: int precision = global_precision; ! 1202: int compromised = 0; ! 1203: int disabled = 0; ! 1204: ! 1205: filepos = ftell(f); ! 1206: fseek(f, keypos, SEEK_SET); ! 1207: while ((status = readkeypacket(f, FALSE, &ctb, (byte *) & timestamp, ! 1208: userid, ! 1209: n, e, NULL, NULL, NULL, NULL, sigkeyID, &keyctrl)) != -1) { ! 1210: if (status == -2 || status == -3) ! 1211: break; ! 1212: if (is_key_ctb(ctb)) { ! 1213: ! 1214: if (keyids) ! 1215: break; ! 1216: extract_keyID(savekeyID, n); ! 1217: keyids++; ! 1218: if (what & SHOW_HASH) ! 1219: getKeyHash(hash, n, e); ! 1220: keyctb = ctb; ! 1221: keystatus = status; /* remember status, could be version error */ ! 1222: ! 1223: } else if (ctb == CTB_KEYCTRL) { ! 1224: ! 1225: /* trust bytes only in public keyrings */ ! 1226: if (keystatus >= 0 && !userids) /* key packet trust byte */ ! 1227: if (keyctrl & KC_DISABLED) ! 1228: disabled = 1; ! 1229: if (what & SHOW_TRUST) ! 1230: print_trust = TRUE; ! 1231: ! 1232: } else if (ctb == CTB_USERID) { ! 1233: ! 1234: if (userids == 0) { ! 1235: PascalToC(userid); /* for display */ ! 1236: ++userids; ! 1237: if (what & SHOW_CHANGE) { ! 1238: show_update(key2IDstring(n)); ! 1239: break; ! 1240: } ! 1241: if (what & SHOW_LISTFMT) { ! 1242: if (is_ctb_type(keyctb, CTB_CERT_PUBKEY_TYPE)) ! 1243: fprintf(pgpout, LANG("pub")); ! 1244: else if (is_ctb_type(keyctb, CTB_CERT_SECKEY_TYPE)) ! 1245: fprintf(pgpout, LANG("sec")); ! 1246: else ! 1247: fprintf(pgpout, "???"); ! 1248: if (keystatus < 0) ! 1249: fprintf(pgpout, "? "); ! 1250: else if (compromised) ! 1251: fprintf(pgpout, "# "); ! 1252: else if (disabled) ! 1253: fprintf(pgpout, "- "); ! 1254: else ! 1255: fprintf(pgpout, " "); ! 1256: fprintf(pgpout, "%4d/%s %s ", ! 1257: countbits(n), key2IDstring(n), cdate(×tamp)); ! 1258: fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid)); ! 1259: break; /* only print default userid */ ! 1260: } ! 1261: fprintf(pgpout, LANG("\nKey for user ID: %s\n"), ! 1262: LOCAL_CHARSET(userid)); ! 1263: fprintf(pgpout, LANG("%d-bit key, key ID %s, created %s\n"), ! 1264: countbits(n), key2IDstring(n), cdate(×tamp)); ! 1265: if (keystatus == -4) ! 1266: fprintf(pgpout, LANG("Bad key format.\n")); ! 1267: else if (keystatus == -6) ! 1268: fprintf(pgpout, LANG("Unrecognized version.\n")); ! 1269: else if (what & SHOW_HASH) ! 1270: printKeyHash(hash, FALSE); ! 1271: if (compromised) ! 1272: fprintf(pgpout, LANG("Key has been revoked.\n")); ! 1273: if (disabled) ! 1274: fprintf(pgpout, LANG("Key is disabled.\n")); ! 1275: if (print_trust && *owntrust_msg[TRUST_LEV(keyctrl)] != '\0') ! 1276: fprintf(pgpout, LANG(owntrust_msg[TRUST_LEV(keyctrl)])); ! 1277: } else { ! 1278: PascalToC(userid); ! 1279: if (what != 0) ! 1280: fprintf(pgpout, "\n"); ! 1281: fprintf(pgpout, LANG("Also known as: %s\n"), ! 1282: LOCAL_CHARSET(userid)); ! 1283: } ! 1284: if (print_trust) { ! 1285: read_trust(f, &keyctrl); ! 1286: fprintf(pgpout, LANG(keylegit_msg[keyctrl & KC_LEGIT_MASK])); ! 1287: } /* print_trust */ ! 1288: } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 1289: ! 1290: if (userids == 0) ! 1291: compromised = 1; ! 1292: if (what & SHOW_CHANGE) { ! 1293: show_update(key2IDstring(n)); ! 1294: break; ! 1295: } ! 1296: if (what & SHOW_SIGS) { ! 1297: if (print_trust) { ! 1298: read_trust(f, &keyctrl); ! 1299: fprintf(pgpout, LANG(sigtrust_msg[TRUST_LEV(keyctrl)])); ! 1300: } else { ! 1301: fprintf(pgpout, LANG(" Certified by: ")); ! 1302: } ! 1303: show_userid(f, sigkeyID); ! 1304: } ! 1305: } ! 1306: } ! 1307: if (status == -1 && userids) ! 1308: status = 0; ! 1309: if (!userids && !compromised && (what != SHOW_CHANGE)) { ! 1310: status = -1; ! 1311: fprintf(pgpout, LANG("\nWarning: keyid %4d/%s %s has no user id!\n"), ! 1312: countbits(n), keyIDstring(savekeyID), cdate(×tamp)); ! 1313: } ! 1314: set_precision(precision); ! 1315: fseek(f, filepos, SEEK_SET); ! 1316: return status; ! 1317: } /* show_key */ ! 1318: ! 1319: /* show_update -- this function just prints an update message to ! 1320: * pgpout to inform the user that an update happened. ! 1321: */ ! 1322: void show_update(char *s) ! 1323: { ! 1324: fprintf(pgpout, LANG("Updated keyID: 0x%s\n"), s); ! 1325: } ! 1326: ! 1327: /* ! 1328: * stripped down version of readkeypacket(), the output userid ! 1329: * is a null terminated string. ! 1330: */ ! 1331: int readkpacket(FILE * f, byte * ctb, char *userid, ! 1332: byte * keyID, byte * sigkeyID) ! 1333: { ! 1334: int status; ! 1335: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1336: ! 1337: status = readkeypacket(f, FALSE, ctb, NULL, userid, n, e, ! 1338: NULL, NULL, NULL, NULL, sigkeyID, NULL); ! 1339: ! 1340: if (status < 0) { ! 1341: #ifdef DEBUG ! 1342: if (status < -1) ! 1343: fprintf(stderr, "readkeypacket returned %d\n", status); ! 1344: #endif ! 1345: return status; ! 1346: } ! 1347: if (keyID && is_key_ctb(*ctb)) ! 1348: extract_keyID(keyID, n); ! 1349: ! 1350: if (userid && *ctb == CTB_USERID) ! 1351: PascalToC(userid); ! 1352: ! 1353: return 0; ! 1354: } /* readkpacket */ ! 1355: ! 1356: /* ! 1357: * write trust byte "keyctrl" to file f at file position "pos" ! 1358: */ ! 1359: void write_trust_pos(FILE * f, byte keyctrl, long pos) ! 1360: { ! 1361: long fpos; ! 1362: ! 1363: fpos = ftell(f); ! 1364: fseek(f, pos, SEEK_SET); ! 1365: write_trust(f, keyctrl); ! 1366: fseek(f, fpos, SEEK_SET); ! 1367: } /* write_trust_pos */ ! 1368: ! 1369: /* ! 1370: * read a trust byte packet from file f, the trust byte will be ! 1371: * stored in "keyctrl". ! 1372: * returns -1 on EOF, -3 on corrupt input, and ERR_NOTRUST if ! 1373: * the packet was not a trust byte (this can be used to check if ! 1374: * a file is a keyring (with trust bytes) or a keyfile). ! 1375: * The current file position is left unchanged in this case. ! 1376: */ ! 1377: int read_trust(FILE * f, byte * keyctrl) ! 1378: { ! 1379: unsigned char buf[3]; ! 1380: ! 1381: if (fread(buf, 1, 3, f) != 3) ! 1382: return -1; ! 1383: if (buf[0] != CTB_KEYCTRL) { ! 1384: if (is_ctb(buf[0])) { ! 1385: fseek(f, -3L, SEEK_CUR); ! 1386: return ERR_NOTRUST; ! 1387: } else ! 1388: return -3; /* bad data */ ! 1389: } ! 1390: if (buf[1] != 1) /* length must be 1 */ ! 1391: return -3; ! 1392: if (keyctrl) ! 1393: *keyctrl = buf[2]; ! 1394: return 0; ! 1395: } /* read_trust */ ! 1396: ! 1397: ! 1398: ! 1399: /****** userid lookup ******/ ! 1400: ! 1401: #define HASH_ALLOC (ALLOC_UNIT / sizeof(struct hashent)) ! 1402: ! 1403: static char *store_str(char *str); ! 1404: static VOID *allocbuf(int size); ! 1405: static void freebufpool(); ! 1406: ! 1407: static struct hashent { ! 1408: struct hashent *next; ! 1409: byte keyID[KEYFRAGSIZE]; ! 1410: char *userid; ! 1411: } **hashtbl = NULL, *hashptr; ! 1412: ! 1413: static char *strptr; ! 1414: static int strleft = 0; ! 1415: static int hashleft = 0; ! 1416: static int nleft = 0; ! 1417: ! 1418: #define MAXKR 8 /* max. number of keyrings for user_from_keyID() */ ! 1419: static char *krnames[MAXKR]; ! 1420: static int nkr = 0; ! 1421: ! 1422: /* ! 1423: * Lookup userid by keyID without using the in-memory hash table. ! 1424: */ ! 1425: static char * ! 1426: _user_from_keyID(byte * srch_keyID) ! 1427: { ! 1428: FILE *f; ! 1429: int i, status, found = 0; ! 1430: byte keyID[KEYFRAGSIZE]; ! 1431: static char userid[256]; ! 1432: byte ctb; ! 1433: ! 1434: /* search all keyfiles set with setkrent() */ ! 1435: for (i = 0; !found && i < nkr; ++i) { ! 1436: if ((f = fopen(krnames[i], FOPRBIN)) == NULL) ! 1437: continue; ! 1438: while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1) { ! 1439: if (status == -2 || status == -3) ! 1440: break; ! 1441: if (is_key_ctb(ctb) && memcmp(keyID, srch_keyID, KEYFRAGSIZE) == 0) ! 1442: found = 1; ! 1443: if (found && ctb == CTB_USERID) ! 1444: break; ! 1445: } ! 1446: fclose(f); ! 1447: } ! 1448: return found ? userid : NULL; ! 1449: } /* _user_from_keyID */ ! 1450: ! 1451: /* ! 1452: * Lookup userid by keyID, use hash table if initialized. ! 1453: */ ! 1454: char * ! 1455: user_from_keyID(byte * keyID) ! 1456: { ! 1457: struct hashent *p; ! 1458: ! 1459: if (!hashtbl) ! 1460: return _user_from_keyID(keyID); ! 1461: for (p = hashtbl[PK_HASH(keyID)]; p; p = p->next) ! 1462: if (memcmp(keyID, p->keyID, KEYFRAGSIZE) == 0) ! 1463: return p->userid; ! 1464: return NULL; ! 1465: } /* user_from_keyID */ ! 1466: ! 1467: /* ! 1468: * add keyfile to userid hash table, userids are added, endkrent() clears ! 1469: * the hash table. ! 1470: */ ! 1471: int setkrent(char *keyring) ! 1472: { ! 1473: int i; ! 1474: ! 1475: assert(nkr < MAXKR); ! 1476: if (keyring == NULL) ! 1477: keyring = globalPubringName; ! 1478: for (i = 0; i < nkr; ++i) ! 1479: if (strcmp(keyring, krnames[i]) == 0) ! 1480: return 0; /* duplicate name */ ! 1481: krnames[nkr++] = store_str(keyring); ! 1482: return 0; ! 1483: } /* setkrent */ ! 1484: ! 1485: void endkrent(void) ! 1486: { ! 1487: hashleft = strleft = 0; ! 1488: hashtbl = NULL; ! 1489: nkr = 0; ! 1490: freebufpool(); ! 1491: } /* endkrent */ ! 1492: ! 1493: /* ! 1494: * create userid hash table, read all files set with setkrent() ! 1495: */ ! 1496: int init_userhash(void) ! 1497: { ! 1498: FILE *f; ! 1499: int status, i; ! 1500: byte keyID[KEYFRAGSIZE]; ! 1501: char userid[256]; ! 1502: byte ctb; ! 1503: int keyflag; ! 1504: ! 1505: if (!hashtbl) { ! 1506: hashtbl = allocbuf(PK_HASHSIZE * sizeof(struct hashent *)); ! 1507: memset(hashtbl, 0, PK_HASHSIZE * sizeof(struct hashent *)); ! 1508: } ! 1509: for (i = 0; i < nkr; ++i) { ! 1510: if ((f = fopen(krnames[i], FOPRBIN)) == NULL) ! 1511: continue; ! 1512: keyflag = 0; ! 1513: while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1) { ! 1514: if (is_key_ctb(ctb) && user_from_keyID(keyID) == NULL) ! 1515: keyflag = 1; ! 1516: if (keyflag && ctb == CTB_USERID) { ! 1517: if (!hashleft) { ! 1518: hashptr = allocbuf(HASH_ALLOC * sizeof(struct hashent)); ! 1519: hashleft = HASH_ALLOC; ! 1520: } ! 1521: memcpy(hashptr->keyID, keyID, KEYFRAGSIZE); ! 1522: hashptr->userid = store_str(userid); ! 1523: hashptr->next = hashtbl[PK_HASH(keyID)]; ! 1524: hashtbl[PK_HASH(keyID)] = hashptr; ! 1525: ++hashptr; ! 1526: --hashleft; ! 1527: keyflag = 0; ! 1528: } ! 1529: } ! 1530: fclose(f); ! 1531: } ! 1532: return 0; ! 1533: } /* init_userhash */ ! 1534: ! 1535: /* ! 1536: * memory management routines ! 1537: */ ! 1538: ! 1539: static void maint_init_mem(void) ! 1540: { ! 1541: pkhash = allocbuf(PK_HASHSIZE * sizeof(struct pubkey *)); ! 1542: memset(pkhash, 0, PK_HASHSIZE * sizeof(struct pubkey *)); ! 1543: } ! 1544: ! 1545: static void maint_release_mem(void) ! 1546: { ! 1547: nleft = 0; ! 1548: strleft = 0; ! 1549: pkhash = NULL; ! 1550: freebufpool(); ! 1551: } ! 1552: ! 1553: /* ! 1554: * allocn() does the same as malloc(). Memory is allocated in chunks ! 1555: * of ALLOC_UNIT bytes, all memory can be freed by calling freebufpool(). ! 1556: */ ! 1557: static VOID * ! 1558: allocn(int size) ! 1559: { ! 1560: static char *ptr; ! 1561: #ifndef MSDOS /* don't align on MSDOS to save memory */ ! 1562: size = (size + 3) & ~3; ! 1563: #endif ! 1564: assert(size < ALLOC_UNIT); ! 1565: if (size > nleft) { ! 1566: ptr = allocbuf(ALLOC_UNIT); ! 1567: nleft = ALLOC_UNIT; ! 1568: } ! 1569: nleft -= size; ! 1570: ptr += size; ! 1571: return ptr - size; ! 1572: } /* allocn */ ! 1573: ! 1574: /* ! 1575: * store_str does the same as strdup(), but allocates memory with allocbuf() ! 1576: */ ! 1577: static char * ! 1578: store_str(char *str) ! 1579: { ! 1580: int size = strlen(str) + 1; ! 1581: if (size > ALLOC_UNIT) { ! 1582: fprintf(stderr, "store_str: string too long\n"); ! 1583: return NULL; ! 1584: } ! 1585: if (size > strleft) { ! 1586: strptr = allocbuf(ALLOC_UNIT); ! 1587: strleft = ALLOC_UNIT; ! 1588: } ! 1589: strcpy(strptr, str); ! 1590: strptr += size; ! 1591: strleft -= size; ! 1592: return strptr - size; ! 1593: } /* store_str */ ! 1594: ! 1595: ! 1596: static struct bufpool { ! 1597: struct bufpool *next; ! 1598: char buf[1]; /* variable size */ ! 1599: } *bufpool = NULL; ! 1600: ! 1601: long totalsize = 0; ! 1602: ! 1603: /* ! 1604: * allocate buffer, all buffers allocated with this function can be ! 1605: * freed with one call to freebufpool() ! 1606: */ ! 1607: static VOID * ! 1608: allocbuf(int size) ! 1609: { ! 1610: struct bufpool *p; ! 1611: ! 1612: p = xmalloc(size + sizeof(struct bufpool *)); ! 1613: totalsize += size; ! 1614: p->next = bufpool; ! 1615: bufpool = p; ! 1616: return p->buf; ! 1617: } /* allocbuf */ ! 1618: ! 1619: /* ! 1620: * free all memory obtained with allocbuf() ! 1621: */ ! 1622: static void freebufpool(void) ! 1623: { ! 1624: struct bufpool *p; ! 1625: ! 1626: if (verbose) ! 1627: fprintf(pgpout, "\nMemory used: %ldk\n", totalsize / 1024); ! 1628: totalsize = 0; ! 1629: while (bufpool) { ! 1630: p = bufpool; ! 1631: bufpool = bufpool->next; ! 1632: free(p); ! 1633: } ! 1634: nleft = strleft = hashleft = 0; ! 1635: } /* freebufpool */ ! 1636: ! 1637: #ifdef MACTC5 ! 1638: void ReInitKeyMaint(void); ! 1639: ! 1640: void ReInitKeyMaint(void) { ! 1641: trustlst_len = 9; ! 1642: legitlst_len = 9; ! 1643: strcpy(floppyring,""); ! 1644: check_only = FALSE; ! 1645: floppy_fp = NULL; ! 1646: pkhash = NULL; ! 1647: pklist = NULL; ! 1648: hashtbl = NULL; ! 1649: totalsize = 0; ! 1650: } ! 1651: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.