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