|
|
1.1.1.9 ! root 1: /* keyadd.c - Keyring merging 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: ! 22: #include <stdio.h> ! 23: #include <stdlib.h> ! 24: #ifdef UNIX ! 25: #include <sys/types.h> ! 26: #endif ! 27: #include <time.h> ! 28: #include "mpilib.h" ! 29: #include "crypto.h" ! 30: #include "fileio.h" ! 31: #include "keymgmt.h" ! 32: #include "charset.h" ! 33: #include "mpiio.h" ! 34: #include "language.h" ! 35: #include "pgp.h" ! 36: #include "exitpgp.h" ! 37: #include "keyadd.h" ! 38: #include "keymaint.h" ! 39: #ifdef MACTC5 ! 40: #include "Macutil2.h" ! 41: #include "Macutil3.h" ! 42: #include "MyBufferedStdio.h" ! 43: #include "ReplaceStdio.h" ! 44: int _addto_keyring(char *keyfile, char *ringfile); ! 45: #endif ! 46: ! 47: void gpk_close(void); ! 48: int gpk_open(char *keyfile); ! 49: int get_publickey(long *file_position, int *pktlen, ! 50: byte * keyID, byte * timestamp, ! 51: byte * userid, unitptr n, unitptr e); ! 52: ! 53: static int ask_to_sign(byte * keyID, char *ringfile); ! 54: static boolean ask_first; ! 55: ! 56: static boolean publickey; /* if TRUE, add trust packets */ ! 57: ! 58: static int newkeys, newsigs, newids, newrvks; ! 59: static byte mykeyID[KEYFRAGSIZE]; ! 60: ! 61: static struct sig_list { ! 62: struct sig_list *next; ! 63: long pos; ! 64: } *siglist; ! 65: static void sig_list_add(long pos) ! 66: { ! 67: struct sig_list *p; ! 68: p = xmalloc(sizeof *p); ! 69: p->pos = pos; ! 70: p->next = siglist; ! 71: siglist = p; ! 72: } ! 73: static int sig_list_find(long pos) ! 74: { ! 75: struct sig_list *p; ! 76: for (p = siglist; p; p = p->next) ! 77: if (p->pos == pos) ! 78: return 1; ! 79: return 0; ! 80: } ! 81: static void sig_list_clear(void) ! 82: { ! 83: struct sig_list *p, *n; ! 84: for (p = siglist; p; p = n) { ! 85: n = p->next; ! 86: free(p); ! 87: } ! 88: siglist = NULL; ! 89: } ! 90: ! 91: /* Merge signatures from userid in fkey (which is keyfile) at keypos with ! 92: * userid from fring (which is ringfile) at ringpos, appending result to out. ! 93: */ ! 94: static int mergesigs(FILE * fkey, char *keyfile, long keypos, FILE * fring, ! 95: char *ringfile, long *pringpos, FILE * out) ! 96: { ! 97: long ringuseridpos, ringpos; ! 98: int ringpktlen, keypktlen; ! 99: int status; ! 100: byte ctb; ! 101: int copying; ! 102: word32 rstamp, kstamp, xstamp; ! 103: byte keyID[KEYFRAGSIZE]; ! 104: char userid[256]; ! 105: ! 106: /* First, copy the userid packet itself, plus any comments or ctrls */ ! 107: ringuseridpos = ringpos = *pringpos; ! 108: fseek(fring, ringpos, SEEK_SET); ! 109: (void) readkeypacket(fring, FALSE, &ctb, NULL, userid, NULL, NULL, ! 110: NULL, NULL, NULL, NULL, NULL, NULL); ! 111: PascalToC(userid); ! 112: ringpktlen = ftell(fring) - ringpos; ! 113: copyfilepos(fring, out, ringpktlen, ringpos); ! 114: for (;;) { ! 115: ringpos = ftell(fring); ! 116: status = nextkeypacket(fring, &ctb); ! 117: if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID || ! 118: is_ctb_type(ctb, CTB_SKE_TYPE)) ! 119: break; ! 120: ringpktlen = ftell(fring) - ringpos; ! 121: copyfilepos(fring, out, ringpktlen, ringpos); ! 122: } ! 123: fseek(fring, ringpos, SEEK_SET); ! 124: ! 125: /* Now, ringpos points just past userid packet and ctrl packet. */ ! 126: /* Advance keypos to the analogous location. */ ! 127: fseek(fkey, keypos, SEEK_SET); ! 128: (void) nextkeypacket(fkey, &ctb); ! 129: for (;;) { ! 130: keypos = ftell(fkey); ! 131: status = nextkeypacket(fkey, &ctb); ! 132: if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID || ! 133: is_ctb_type(ctb, CTB_SKE_TYPE)) ! 134: break; ! 135: } ! 136: fseek(fkey, keypos, SEEK_SET); ! 137: ! 138: /* Second, copy all keyfile signatures that aren't in ringfile. ! 139: */ ! 140: ! 141: copying = FALSE; ! 142: for (;;) { ! 143: /* Read next sig from keyfile; see if it is in ringfile; ! 144: * if it is not a signature, ignore it, ! 145: * if it is absent from ringfile, copy it, ! 146: * if it is present, and the timestamp is not newer, ignore it, ! 147: * if present and newer, replace old with new. ! 148: * Loop till hit a new key or userid in keyfile, or EOF. ! 149: */ ! 150: keypos = ftell(fkey); ! 151: status = readkeypacket(fkey, FALSE, &ctb, (byte *) & kstamp, ! 152: NULL, NULL, NULL, ! 153: NULL, NULL, NULL, NULL, keyID, NULL); ! 154: #ifdef MACTC5 ! 155: mac_poll_for_break(); ! 156: #endif ! 157: if (status == -3) /* unrecoverable error: bad packet ! 158: length etc. */ ! 159: return status; ! 160: keypktlen = ftell(fkey) - keypos; ! 161: if (status == -1 || is_key_ctb(ctb) || ctb == CTB_USERID) ! 162: break; /* EOF or next key/userid */ ! 163: if (status < 0) ! 164: continue; /* bad packet, skip it */ ! 165: if (is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 166: long sig_pos; ! 167: int sig_len; ! 168: /* Set copying true if signature is not in the ringfile */ ! 169: copying = (getpubusersig(ringfile, ringuseridpos, ! 170: keyID, (byte *) & rstamp, ! 171: &sig_pos, ! 172: &sig_len) < 0); ! 173: if (!copying) { ! 174: long save_pos = ftell(fkey); ! 175: fseek(fkey, keypos + 6, SEEK_SET); ! 176: fread(&kstamp, 1, SIZEOF_TIMESTAMP, fkey); ! 177: fseek(fkey, save_pos, SEEK_SET); ! 178: convert_byteorder((byte *) & kstamp, SIZEOF_TIMESTAMP); ! 179: if (verbose) ! 180: fprintf(pgpout, "ring: %lx key: %lx\n", rstamp, kstamp); ! 181: if (kstamp > rstamp) { /* Update, Maybe */ ! 182: char *signator; ! 183: if ((signator = user_from_keyID(keyID)) == NULL) { ! 184: fprintf(pgpout, ! 185: LANG("Replacing signature from keyID %s on userid \"%s\"\n"), ! 186: keyIDstring(keyID), LOCAL_CHARSET(userid)); ! 187: /* No pubkey for KeyID, no update! */ ! 188: } else { ! 189: long save_keypos; ! 190: long save_ringpos; ! 191: long KeyIDpos; ! 192: int KeyIDlen; ! 193: byte sigClass; ! 194: fprintf(pgpout, ! 195: LANG("Verifying signature from %s\n"), ! 196: LOCAL_CHARSET(signator)); ! 197: fprintf(pgpout, LANG("on userid \"%s\"\n"), ! 198: LOCAL_CHARSET(userid)); ! 199: save_keypos = ftell(fkey); ! 200: save_ringpos = ftell(fring); ! 201: status = getpublickey(GPK_GIVEUP, ringfile, ! 202: &KeyIDpos, &KeyIDlen, NULL, ! 203: NULL, (byte *) userid, NULL, ! 204: NULL); ! 205: if (!status) ! 206: status = check_key_sig(fring, ! 207: KeyIDpos, KeyIDlen, ! 208: userid, fkey, keypos, ! 209: ringfile, NULL, ! 210: (byte *) & xstamp, ! 211: &sigClass); ! 212: PascalToC(userid); ! 213: PascalToC(signator); ! 214: if (!status) { ! 215: fprintf(pgpout, ! 216: LANG("Replacing signature from %s\n"), ! 217: LOCAL_CHARSET(signator)); ! 218: fprintf(pgpout, ! 219: LANG("on userid \"%s\"\n"), ! 220: LOCAL_CHARSET(userid)); ! 221: sig_list_add(sig_pos); ! 222: ++newsigs; ! 223: copying = 1; ! 224: } else ! 225: fprintf(pgpout, LANG("Verification Failed\n")); ! 226: fseek(fring, save_ringpos, SEEK_SET); ! 227: fseek(fkey, save_keypos, SEEK_SET); ! 228: } ! 229: } ! 230: } else { ! 231: char *signator; ! 232: if ((signator = user_from_keyID(keyID)) == NULL) ! 233: fprintf(pgpout, ! 234: LANG("New signature from keyID %s on userid \"%s\"\n"), ! 235: keyIDstring(keyID), LOCAL_CHARSET(userid)); ! 236: else { ! 237: fprintf(pgpout, ! 238: LANG("New signature from %s\n"), ! 239: LOCAL_CHARSET(signator)); ! 240: fprintf(pgpout, ! 241: LANG("on userid \"%s\"\n"), LOCAL_CHARSET(userid)); ! 242: } ! 243: ++newsigs; ! 244: if (batchmode) ! 245: show_update(keyIDstring(mykeyID)); ! 246: } ! 247: } ! 248: if (copying && is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 249: copyfilepos(fkey, out, keypktlen, keypos); ! 250: if (publickey) ! 251: write_trust(out, KC_SIGTRUST_UNDEFINED); ! 252: } ! 253: } ! 254: ! 255: /* Third, for all ring sig's which are not replaced, copy to output */ ! 256: fseek(fring, ringpos, SEEK_SET); ! 257: for (;;) { ! 258: ringpos = ftell(fring); ! 259: if (sig_list_find(ringpos)) { ! 260: /* skip signature packet */ ! 261: nextkeypacket(fring, &ctb); ! 262: ringpos = ftell(fring); ! 263: /* skip trust packet, if present */ ! 264: if (nextkeypacket(fring, &ctb) < 0 || ctb != CTB_KEYCTRL) ! 265: fseek(fring, ringpos, SEEK_SET); ! 266: continue; ! 267: } ! 268: status = nextkeypacket(fring, &ctb); ! 269: ringpktlen = ftell(fring) - ringpos; ! 270: if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID) ! 271: break; ! 272: copyfilepos(fring, out, ringpktlen, ringpos); ! 273: } /* End of loop for each sig in ringfile */ ! 274: sig_list_clear(); ! 275: fseek(fring, ringpos, SEEK_SET); ! 276: *pringpos = ringpos; ! 277: return 0; ! 278: } /* mergesigs */ ! 279: ! 280: /* Merge key from fkey (which is keyfile) at keypos with key from ! 281: * fring (which is ringfile) at ringpos, appending result to out. ! 282: */ ! 283: static int mergekeys(FILE * fkey, char *keyfile, long keypos, FILE * fring, ! 284: char *ringfile, long *pringpos, FILE * out) ! 285: { ! 286: long ringkeypos, keykeypos, ringpos; ! 287: int ringpktlen, keypktlen; ! 288: int status; ! 289: byte ctb; ! 290: int copying; ! 291: boolean ring_compromise = FALSE; ! 292: byte userid[256]; ! 293: ! 294: /* First, copy the key packet itself, plus any comments or ctrls */ ! 295: ringkeypos = ringpos = *pringpos; ! 296: fseek(fring, ringpos, SEEK_SET); ! 297: (void) nextkeypacket(fring, &ctb); ! 298: ringpktlen = ftell(fring) - ringpos; ! 299: copyfilepos(fring, out, ringpktlen, ringpos); ! 300: for (;;) { ! 301: ringpos = ftell(fring); ! 302: status = nextkeypacket(fring, &ctb); ! 303: if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID) ! 304: break; ! 305: if (is_ctb_type(ctb, CTB_SKE_TYPE)) ! 306: ring_compromise = TRUE; /* compromise cert on keyring */ ! 307: ringpktlen = ftell(fring) - ringpos; ! 308: copyfilepos(fring, out, ringpktlen, ringpos); ! 309: } ! 310: fseek(fring, ringpos, SEEK_SET); ! 311: ! 312: /* Now, ringpos points just past key packet and ctrl packet. */ ! 313: /* Advance keypos to the analogous location. */ ! 314: fseek(fkey, keypos, SEEK_SET); ! 315: keykeypos = keypos; ! 316: (void) nextkeypacket(fkey, &ctb); ! 317: keypktlen = ftell(fkey) - keypos; /* for check_key_sig() */ ! 318: for (;;) { ! 319: keypos = ftell(fkey); ! 320: status = nextkeypacket(fkey, &ctb); ! 321: if (status < 0 || ctb == CTB_USERID || is_ctb_type(ctb, CTB_SKE_TYPE)) ! 322: break; ! 323: } ! 324: if (!ring_compromise && is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 325: /* found a compromise cert on keyfile that is not in ringfile */ ! 326: word32 timestamp; ! 327: byte sig_class; ! 328: int cert_pktlen; ! 329: ! 330: cert_pktlen = ftell(fkey) - keypos; ! 331: if (check_key_sig(fkey, keykeypos, keypktlen, ! 332: (char *) userid, fkey, keypos, ! 333: ringfile, (char *) userid, (byte *) & timestamp, ! 334: &sig_class) == 0 && ! 335: sig_class == KC_SIGNATURE_BYTE) { ! 336: PascalToC((char *) userid); ! 337: fprintf(pgpout, LANG("Key revocation certificate from \"%s\".\n"), ! 338: LOCAL_CHARSET((char *) userid)); ! 339: copyfilepos(fkey, out, cert_pktlen, keypos); ! 340: /* Show updates */ ! 341: if (batchmode) ! 342: show_key(fring, *pringpos, SHOW_CHANGE); ! 343: ++newrvks; ! 344: } else ! 345: fprintf(pgpout, ! 346: LANG("\n\007WARNING: File '%s' contains bad revocation certificate.\n"), ! 347: keyfile); ! 348: } ! 349: fseek(fkey, keypos, SEEK_SET); ! 350: ! 351: /* Second, copy all keyfile userid's plus signatures that aren't ! 352: * in ringfile. ! 353: */ ! 354: ! 355: copying = FALSE; ! 356: for (;;) { ! 357: /* Read next userid from keyfile; see if it is in ringfile; ! 358: * set copying true/false accordingly. If copying is true ! 359: * and it is a userid or a signature, copy it. Loop till hit ! 360: * a new key in keyfile, or EOF. ! 361: */ ! 362: keypos = ftell(fkey); ! 363: status = readkeypacket(fkey, FALSE, &ctb, NULL, (char *) userid, NULL, ! 364: NULL, NULL, NULL, NULL, NULL, NULL, NULL); ! 365: if (status == -3) /* unrecoverable error: bad packet length etc. */ ! 366: return status; ! 367: keypktlen = ftell(fkey) - keypos; ! 368: if (status == -1 || is_key_ctb(ctb)) ! 369: break; /* EOF or next key */ ! 370: if (status < 0) ! 371: continue; /* bad packet, skip it */ ! 372: if (ctb == CTB_USERID) { ! 373: long userid_pos; ! 374: int userid_len; ! 375: PascalToC((char *) userid); ! 376: /* Set copying true if userid is not in the ringfile */ ! 377: copying = (getpubuserid(ringfile, ringkeypos, userid, &userid_pos, ! 378: &userid_len, TRUE) < 0); ! 379: if (copying) { ! 380: putc('\n', pgpout); ! 381: fprintf(pgpout, LANG("New userid: \"%s\".\n"), ! 382: LOCAL_CHARSET((char *) userid)); ! 383: fprintf(pgpout, ! 384: LANG("\nWill be added to the following key:\n")); ! 385: show_key(fring, *pringpos, 0); ! 386: fprintf(pgpout, LANG("\nAdd this userid (y/N)? ")); ! 387: if (batchmode || getyesno('n')) { ! 388: ++newids; ! 389: /* Show an update string */ ! 390: if (batchmode) { ! 391: fprintf(pgpout, "\n"); ! 392: show_key(fring, *pringpos, SHOW_CHANGE); ! 393: } ! 394: } else { ! 395: copying = FALSE; ! 396: } ! 397: } ! 398: } ! 399: if (copying) { ! 400: if (ctb == CTB_USERID || is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 401: copyfilepos(fkey, out, keypktlen, keypos); ! 402: if (publickey) { ! 403: if (is_ctb_type(ctb, CTB_SKE_TYPE)) ! 404: write_trust(out, KC_SIGTRUST_UNDEFINED); ! 405: else ! 406: write_trust(out, KC_LEGIT_UNKNOWN); ! 407: } ! 408: } ! 409: } ! 410: } ! 411: ! 412: /* Third, for all ring userid's, if not in keyfile, copy the userid ! 413: * plus its dependant signatures. ! 414: */ ! 415: fseek(fring, ringpos, SEEK_SET); ! 416: /* Grab the keyID here */ ! 417: readkeypacket(fring, FALSE, &ctb, NULL, (char *) userid, NULL, NULL, ! 418: NULL, NULL, NULL, NULL, NULL, NULL); ! 419: fseek(fring, ringpos, SEEK_SET); ! 420: for (;;) { ! 421: ringpos = ftell(fring); ! 422: status = readkeypacket(fring, FALSE, &ctb, NULL, ! 423: (char *) userid, NULL, NULL, ! 424: NULL, NULL, NULL, NULL, NULL, NULL); ! 425: ringpktlen = ftell(fring) - ringpos; ! 426: if (status == -3) ! 427: return status; ! 428: if (status == -1 || is_key_ctb(ctb)) ! 429: break; ! 430: if (ctb == CTB_USERID) { ! 431: long userid_pos; ! 432: int userid_len; ! 433: /* See if there is a match in keyfile */ ! 434: PascalToC((char *) userid); ! 435: /* don't use substring match (exact_match = TRUE) */ ! 436: if (getpubuserid(keyfile, keykeypos, userid, ! 437: &userid_pos, &userid_len, TRUE) >= 0) { ! 438: if ((status = mergesigs(fkey, keyfile, userid_pos, ! 439: fring, ringfile, &ringpos, out)) < 0) ! 440: return status; ! 441: copying = FALSE; ! 442: } else { ! 443: copying = TRUE; ! 444: } ! 445: } ! 446: if (copying) { ! 447: /* Copy ringfile userid and sigs to out */ ! 448: copyfilepos(fring, out, ringpktlen, ringpos); ! 449: } ! 450: } /* End of loop for each key in ringfile */ ! 451: fseek(fring, ringpos, SEEK_SET); ! 452: *pringpos = ringpos; ! 453: return 0; ! 454: } /* mergekeys */ ! 455: ! 456: /* Adds (prepends) key file to key ring file. */ ! 457: int _addto_keyring(char *keyfile, char *ringfile) ! 458: { ! 459: FILE *f, *g, *h; ! 460: long file_position, fp; ! 461: int pktlen; ! 462: byte ctb; ! 463: int status; ! 464: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 465: unit n1[MAX_UNIT_PRECISION]; ! 466: byte keyID[KEYFRAGSIZE]; ! 467: byte userid[256]; /* key certificate userid */ ! 468: byte userid1[256]; ! 469: word32 tstamp; ! 470: byte *timestamp = (byte *) & tstamp; /* key certificate timestamp */ ! 471: boolean userid_seen = FALSE; ! 472: int commonkeys = 0; ! 473: int copying; ! 474: struct newkey *nkey, *nkeys = NULL; ! 475: char *scratchf; ! 476: ! 477: /* open file f for read, in binary (not text) mode... */ ! 478: if ((f = fopen(keyfile, FOPRBIN)) == NULL) { ! 479: fprintf(pgpout, LANG("\n\007Can't open key file '%s'\n"), keyfile); ! 480: return -1; ! 481: } ! 482: ctb = 0; ! 483: if (fread(&ctb, 1, 1, f) != 1 || !is_key_ctb(ctb)) { ! 484: fclose(f); ! 485: return -1; ! 486: } ! 487: rewind(f); ! 488: ! 489: setoutdir(ringfile); ! 490: scratchf = tempfile(0); ! 491: ! 492: /* ! 493: * get userids from both files, maybe should also use the default public ! 494: * keyring if ringfile is not the default ring. ! 495: */ ! 496: setkrent(ringfile); ! 497: setkrent(keyfile); ! 498: init_userhash(); ! 499: ! 500: if (!file_exists(ringfile)) { ! 501: /* ringfile does not exist. Can it be created? */ ! 502: /* open file g for writing, in binary (not text) mode... */ ! 503: g = fopen(ringfile, FOPWBIN); ! 504: if (g == NULL) { ! 505: fprintf(pgpout, ! 506: LANG("\nKey ring file '%s' cannot be created.\n"), ! 507: ringfile); ! 508: fclose(f); ! 509: goto err; ! 510: } ! 511: fclose(g); ! 512: } ! 513: /* Create working output file */ ! 514: /* open file g for writing, in binary (not text) mode... */ ! 515: if ((g = fopen(scratchf, FOPWBIN)) == NULL) { ! 516: fclose(f); ! 517: goto err; ! 518: } ! 519: newkeys = newsigs = newids = newrvks = 0; ! 520: ! 521: /* Pass 1 - copy all keys from f which aren't in ring file */ ! 522: /* Also copy userid and signature packets. */ ! 523: fprintf(pgpout, LANG("\nLooking for new keys...\n")); ! 524: copying = FALSE; ! 525: if (gpk_open(ringfile) < 0) { ! 526: fclose(f); /* close key file */ ! 527: fclose(g); ! 528: goto err; ! 529: } ! 530: for (;;) { ! 531: file_position = ftell(f); ! 532: ! 533: status = readkeypacket(f, FALSE, &ctb, ! 534: timestamp, (char *) userid, n, e, ! 535: NULL, NULL, NULL, NULL, NULL, NULL); ! 536: /* Note that readkeypacket has called set_precision */ ! 537: if (status == -1) /* EOF */ ! 538: break; ! 539: if (status == -2 || status == -3) { ! 540: fprintf(pgpout, ! 541: LANG("\n\007Could not read key from file '%s'.\n"), ! 542: keyfile); ! 543: fclose(f); /* close key file */ ! 544: fclose(g); ! 545: goto err; ! 546: } ! 547: if (status < 0) { ! 548: copying = FALSE; ! 549: continue; /* don't merge keys from unrecognized version */ ! 550: } ! 551: #ifdef MACTC5 ! 552: mac_poll_for_break(); ! 553: #endif ! 554: /* Check to see if key is already on key ring */ ! 555: if (is_key_ctb(ctb)) { ! 556: extract_keyID(keyID, n); /* from keyfile, not ringfile */ ! 557: publickey = is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE); ! 558: ! 559: /* Check for duplicate key in key ring: */ ! 560: status = get_publickey(&fp, NULL, keyID, timestamp, userid, n1, e); ! 561: if (status == 0) { ! 562: /* key in both keyring and keyfile */ ! 563: if (mp_compare(n, n1) != 0) { ! 564: fprintf(pgpout, ! 565: LANG("\n\007Warning: Key ID %s matches key ID of key already on \n\ ! 566: key ring '%s', but the keys themselves differ.\n\ ! 567: This is highly suspicious. This key will not be added to ring.\n\ ! 568: Acknowledge by pressing return: "), keyIDstring(keyID), ringfile); ! 569: getyesno('n'); ! 570: } else { ! 571: ++commonkeys; ! 572: } ! 573: copying = FALSE; ! 574: } else if (status == -1) { /* key NOT in keyring */ ! 575: ++newkeys; ! 576: if (interactive_add) { ! 577: if (!show_key(f, file_position, SHOW_ALL)) { ! 578: fprintf(pgpout, ! 579: LANG("\nDo you want to add this key to keyring '%s' (y/N)? "), ! 580: ringfile); ! 581: copying = getyesno('n'); ! 582: } else ! 583: copying = FALSE; ! 584: } else { ! 585: if (!show_key(f, file_position, SHOW_LISTFMT)) ! 586: copying = TRUE; ! 587: else ! 588: copying = FALSE; ! 589: } ! 590: ! 591: /* If batchmode, output an update message */ ! 592: if (batchmode) ! 593: show_key(f, file_position, SHOW_CHANGE); ! 594: if (copying) { ! 595: nkey = xmalloc(sizeof(*nkey)); ! 596: memcpy(nkey->keyID, keyID, KEYFRAGSIZE); ! 597: nkey->next = nkeys; ! 598: nkeys = nkey; ! 599: } ! 600: } else { ! 601: /* unknown version or bad key */ ! 602: copying = FALSE; ! 603: } ! 604: } ! 605: /* ! 606: * Now, we copy according to the copying flag ! 607: * The key is prepended to the ring to give it search ! 608: * precedence over other keys with that same userid. ! 609: */ ! 610: if (copying && (is_key_ctb(ctb) || ctb == CTB_USERID || ! 611: is_ctb_type(ctb, CTB_SKE_TYPE))) { ! 612: pktlen = (int) (ftell(f) - file_position); ! 613: copyfilepos(f, g, pktlen, file_position); /* copy packet from f */ ! 614: if (publickey) { ! 615: /* Initialize trust packets after keys and signatures */ ! 616: if (is_key_ctb(ctb)) { ! 617: write_trust(g, KC_OWNERTRUST_UNDEFINED); ! 618: userid_seen = FALSE; ! 619: } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 620: if (userid_seen) { ! 621: write_trust(g, KC_SIGTRUST_UNDEFINED); ! 622: } else { ! 623: /* signature certificate before userid must be compromise cert. */ ! 624: fprintf(pgpout, LANG("Key has been revoked.\n")); ! 625: } ! 626: } else if (is_ctb_type(ctb, CTB_USERID_TYPE)) { ! 627: write_trust(g, KC_LEGIT_UNKNOWN); ! 628: userid_seen = TRUE; ! 629: } ! 630: } ! 631: } ! 632: } ! 633: gpk_close(); ! 634: ! 635: /* ! 636: * Now copy the remainder of the ringfile, h, to g. commonkeys tells ! 637: * how many keys are common to keyfile and ringfile. As long as that ! 638: * is nonzero we will check each key in ringfile to see if it has a ! 639: * match in keyfile. ! 640: */ ! 641: if ((h = fopen(ringfile, FOPRBIN)) != NULL) { ! 642: if (gpk_open(keyfile) < 0) { ! 643: fclose(f); ! 644: fclose(g); ! 645: fclose(h); ! 646: goto err; ! 647: } ! 648: while (commonkeys) { ! 649: /* Loop for each key in ringfile */ ! 650: file_position = ftell(h); ! 651: status = readkeypacket(h, FALSE, &ctb, NULL, (char *) userid, n, e, ! 652: NULL, NULL, NULL, NULL, NULL, NULL); ! 653: if (status == -1 || status == -3) { ! 654: if (status == -1) /* hit EOF */ ! 655: fprintf(pgpout, ! 656: LANG("\n\007Key file contains duplicate keys: cannot be added to keyring\n")); ! 657: else ! 658: fprintf(pgpout, ! 659: LANG("\n\007Could not read key from file '%s'.\n"), ! 660: ringfile); ! 661: fclose(f); ! 662: fclose(g); ! 663: fclose(h); ! 664: goto err; ! 665: } ! 666: PascalToC((char *) userid); ! 667: pktlen = ftell(h) - file_position; ! 668: if (is_key_ctb(ctb)) { ! 669: long tfp; ! 670: /* unknown version or bad data: copy (don't remove packets from ringfile) */ ! 671: copying = TRUE; ! 672: if (status == 0) { ! 673: /* See if there is a match in keyfile */ ! 674: extract_keyID(keyID, n); /* from ringfile, ! 675: not keyfile */ ! 676: extract_keyID(mykeyID, n); /* save this */ ! 677: publickey = is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE); ! 678: if ((status = get_publickey(&tfp, NULL, keyID, ! 679: timestamp, userid1, n1, e)) >= 0) { ! 680: if (verbose) ! 681: fprintf(pgpout, ! 682: "Merging key ID: %s\n", ! 683: keyIDstring(keyID)); ! 684: if (mergekeys(f, keyfile, tfp, h, ! 685: ringfile, &file_position, g) < 0) { ! 686: fclose(f); ! 687: fclose(g); ! 688: fclose(h); ! 689: goto err; ! 690: } ! 691: copying = FALSE; ! 692: --commonkeys; ! 693: } else { ! 694: if (status == -3) ! 695: --commonkeys; /* missing userid packet? */ ! 696: } ! 697: } ! 698: } ! 699: if (copying) { ! 700: /* Copy ringfile key to g, without its sigs */ ! 701: copyfilepos(h, g, pktlen, file_position); ! 702: file_position += pktlen; ! 703: } ! 704: } /* End of loop for each key in ringfile */ ! 705: gpk_close(); ! 706: copyfile(h, g, -1L); /* copy rest of file from file h to g */ ! 707: fclose(h); ! 708: } ! 709: fclose(f); ! 710: if (write_error(g)) { ! 711: fclose(g); ! 712: goto err; ! 713: } ! 714: fclose(g); ! 715: if (newsigs == 0 && newkeys == 0 && newids == 0 && newrvks == 0) { ! 716: fprintf(pgpout, LANG("No new keys or signatures in keyfile.\n")); ! 717: rmtemp(scratchf); ! 718: endkrent(); ! 719: return 0; ! 720: } ! 721: if (status = dokeycheck(NULL, scratchf, CHECK_NEW)) { ! 722: if (verbose) ! 723: fprintf(pgpout, "addto_keyring: dokeycheck returned %d\n", status); ! 724: goto err; ! 725: } ! 726: endkrent(); ! 727: ! 728: fprintf(pgpout, LANG("\nKeyfile contains:\n")); ! 729: if (newkeys) ! 730: fprintf(pgpout, LANG("%4d new key(s)\n"), newkeys); ! 731: if (newsigs) ! 732: fprintf(pgpout, LANG("%4d new signatures(s)\n"), newsigs); ! 733: if (newids) ! 734: fprintf(pgpout, LANG("%4d new user ID(s)\n"), newids); ! 735: if (newrvks) ! 736: fprintf(pgpout, LANG("%4d new revocation(s)\n"), newrvks); ! 737: ! 738: ask_first = TRUE; ! 739: status = maint_update(scratchf, nkeys); ! 740: if (status >= 0 && !filter_mode && !batchmode) ! 741: for (nkey = nkeys; nkey; nkey = nkey->next) ! 742: if (ask_to_sign(nkey->keyID, scratchf) != 0) ! 743: break; ! 744: if (status && verbose) ! 745: fprintf(pgpout, "addto_keyring: maint_update returned %d\n", status); ! 746: ! 747: free_newkeys(nkeys); ! 748: ! 749: savetempbak(scratchf, ringfile); ! 750: ! 751: #ifdef MACTC5 ! 752: { ! 753: byte header[8]; ! 754: get_header_info_from_file(ringfile, header, 8 ); ! 755: if (header[0] == CTB_CERT_SECKEY) ! 756: PGPSetFinfo(ringfile,'SKey','MPGP'); ! 757: if (header[0] == CTB_CERT_PUBKEY) ! 758: PGPSetFinfo(ringfile,'PKey','MPGP'); ! 759: } ! 760: #endif ! 761: ! 762: return 0; /* normal return */ ! 763: ! 764: err: ! 765: gpk_close(); /* save to call if not opened */ ! 766: endkrent(); ! 767: /* make sure we remove any garbage files we may have created */ ! 768: rmtemp(scratchf); ! 769: return -1; ! 770: } /* _addto_keyring */ ! 771: ! 772: int addto_keyring(char *keyfile, char *ringfile) ! 773: { ! 774: long armorline = 0; ! 775: char *tempf; ! 776: int addflag = 0; ! 777: ! 778: if (_addto_keyring(keyfile, ringfile) == 0) ! 779: return 0; ! 780: /* check if the keyfile to be added is armored */ ! 781: while (is_armor_file(keyfile, armorline)) { ! 782: tempf = tempfile(TMP_TMPDIR | TMP_WIPE); ! 783: if (de_armor_file(keyfile, tempf, &armorline)) { ! 784: rmtemp(tempf); ! 785: return -1; ! 786: } ! 787: if (_addto_keyring(tempf, ringfile) == 0) ! 788: addflag = 1; ! 789: rmtemp(tempf); ! 790: } ! 791: if (!addflag) { ! 792: fprintf(pgpout, LANG("\nNo keys found in '%s'.\n"), keyfile); ! 793: return -1; ! 794: } else { ! 795: return 0; ! 796: } ! 797: } ! 798: ! 799: static int ask_to_sign(byte * keyID, char *ringfile) ! 800: { ! 801: FILE *f; ! 802: word32 timestamp; ! 803: byte ctb, trust; ! 804: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 805: byte userid[256]; ! 806: long fpos; ! 807: int status; ! 808: extern char my_name[]; ! 809: ! 810: if (getpublickey(GPK_GIVEUP, ringfile, &fpos, NULL, keyID, ! 811: (byte *) & timestamp, userid, n, e) < 0) ! 812: return -1; ! 813: ! 814: if ((f = fopen(ringfile, FOPRBIN)) == NULL) ! 815: return -1; ! 816: ! 817: fseek(f, fpos, SEEK_SET); ! 818: if (is_compromised(f)) { ! 819: fclose(f); ! 820: return 0; ! 821: } ! 822: if (nextkeypacket(f, &ctb) < 0) { ! 823: fclose(f); ! 824: return -1; ! 825: } ! 826: if (ctb != CTB_CERT_PUBKEY) { ! 827: fclose(f); ! 828: return 0; /* don't ask to sign secret key */ ! 829: } ! 830: while (nextkeypacket(f, &ctb) == 0 && !is_key_ctb(ctb)) ! 831: if (ctb == CTB_USERID) /* check first userid */ ! 832: break; ! 833: if (ctb != CTB_USERID) { ! 834: fclose(f); ! 835: return -1; ! 836: } ! 837: if ((status = read_trust(f, &trust)) < 0) { ! 838: fclose(f); ! 839: return status; ! 840: } ! 841: if ((trust & KC_LEGIT_MASK) == KC_LEGIT_COMPLETE) { ! 842: fclose(f); ! 843: return 0; ! 844: } ! 845: if (ask_first) { ! 846: /* shortcut for adding big keyfile */ ! 847: fprintf(pgpout, ! 848: LANG("\nOne or more of the new keys are not fully certified.\n\ ! 849: Do you want to certify any of these keys yourself (y/N)? ")); ! 850: if (!getyesno('n')) { ! 851: fclose(f); ! 852: return 1; ! 853: } ! 854: } ! 855: ask_first = FALSE; ! 856: show_key(f, fpos, SHOW_ALL | SHOW_HASH); ! 857: fclose(f); ! 858: PascalToC((char *) userid); ! 859: fprintf(pgpout, ! 860: LANG("\nDo you want to certify this key yourself (y/N)? ")); ! 861: if (getyesno('n')) { ! 862: if (signkey((char *) userid, my_name, ringfile) == 0) ! 863: maint_update(ringfile, 0); ! 864: } ! 865: return 0; ! 866: } ! 867: ! 868: /**** faster version of getpublickey() ****/ ! 869: ! 870: static long find_keyID(byte * keyID); ! 871: ! 872: static FILE *gpkf = NULL; ! 873: ! 874: /* ! 875: * speedup replacement for getpublickey(), does not have the arguments ! 876: * giveup, showkey and keyfile (giveup = TRUE, showkey = FALSE, keyfile ! 877: * is set with gpk_open(). ! 878: * only searches on keyID ! 879: */ ! 880: int get_publickey(long *file_position, int *pktlen, byte * keyID, ! 881: byte * timestamp, byte * userid, unitptr n, unitptr e) ! 882: { ! 883: byte ctb; /* returned by readkeypacket */ ! 884: int status, keystatus = -1; ! 885: long fpos; ! 886: ! 887: if ((fpos = find_keyID(keyID)) == -1) ! 888: return -1; ! 889: fseek(gpkf, fpos, SEEK_SET); ! 890: ! 891: for (;;) { ! 892: fpos = ftell(gpkf); ! 893: status = readkeypacket(gpkf, FALSE, &ctb, timestamp, ! 894: (char *) userid, n, e, ! 895: NULL, NULL, NULL, NULL, NULL, NULL); ! 896: /* Note that readkeypacket has called set_precision */ ! 897: ! 898: if (status < 0 && status != -4 && status != -6) ! 899: return status; ! 900: ! 901: /* Remember packet position and size for last key packet */ ! 902: if (is_key_ctb(ctb)) { ! 903: if (file_position) ! 904: *file_position = fpos; ! 905: if (pktlen) ! 906: *pktlen = (int) (ftell(gpkf) - fpos); ! 907: if (keystatus != -1) ! 908: return -3; /* should not happen, probably missing userid pkt */ ! 909: keystatus = status; ! 910: } ! 911: if (ctb == CTB_USERID) ! 912: return keystatus; ! 913: } ! 914: } ! 915: ! 916: #define PK_HASHSIZE 256 /* must be power of 2 */ ! 917: #define PK_HASH(x) (*(byte *) (x) & (PK_HASHSIZE - 1)) ! 918: #define HASH_ALLOC 400 ! 919: ! 920: static VOID *allocbuf(int size); ! 921: static void freebufpool(void); ! 922: ! 923: static struct hashent { ! 924: struct hashent *next; ! 925: byte keyID[KEYFRAGSIZE]; ! 926: long offset; ! 927: } **hashtbl = NULL, *hashptr; ! 928: ! 929: static int hashleft = 0; ! 930: ! 931: int gpk_open(char *keyfile) ! 932: { ! 933: int status; ! 934: long fpos = 0; ! 935: byte keyID[KEYFRAGSIZE]; ! 936: byte ctb; ! 937: ! 938: if (gpkf) { ! 939: fprintf(pgpout, "gpk_open: already open\n"); ! 940: return -1; ! 941: } ! 942: default_extension(keyfile, PGP_EXTENSION); ! 943: if ((gpkf = fopen(keyfile, FOPRBIN)) == NULL) ! 944: return -1; /* error return */ ! 945: hashtbl = allocbuf(PK_HASHSIZE * sizeof(struct hashent *)); ! 946: memset(hashtbl, 0, PK_HASHSIZE * sizeof(struct hashent *)); ! 947: while ((status = readkpacket(gpkf, &ctb, NULL, keyID, NULL)) != -1) { ! 948: if (status == -2 || status == -3) { ! 949: fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"), ! 950: keyfile); ! 951: fclose(gpkf); /* close key file */ ! 952: return -1; ! 953: } ! 954: if (is_key_ctb(ctb)) { ! 955: if (status != -4) { ! 956: if (find_keyID(keyID) != -1) ! 957: fprintf(pgpout, ! 958: "Warning: duplicate key in keyring '%s'\n", keyfile); ! 959: if (!hashleft) { ! 960: hashptr = allocbuf(HASH_ALLOC * sizeof(struct hashent)); ! 961: hashleft = HASH_ALLOC; ! 962: } ! 963: memcpy(hashptr->keyID, keyID, KEYFRAGSIZE); ! 964: hashptr->offset = fpos; ! 965: hashptr->next = hashtbl[PK_HASH(keyID)]; ! 966: hashtbl[PK_HASH(keyID)] = hashptr; ! 967: ++hashptr; ! 968: --hashleft; ! 969: } ! 970: } ! 971: fpos = ftell(gpkf); ! 972: } ! 973: return 0; ! 974: } ! 975: ! 976: void gpk_close(void) ! 977: { ! 978: if (!gpkf) ! 979: return; ! 980: hashleft = 0; ! 981: hashtbl = NULL; ! 982: freebufpool(); ! 983: fclose(gpkf); /* close key file */ ! 984: gpkf = NULL; ! 985: } ! 986: ! 987: /* ! 988: * Lookup file position in hash table by keyID, returns -1 if not found ! 989: */ ! 990: static long find_keyID(byte * keyID) ! 991: { ! 992: struct hashent *p; ! 993: ! 994: for (p = hashtbl[PK_HASH(keyID)]; p; p = p->next) ! 995: if (memcmp(keyID, p->keyID, KEYFRAGSIZE) == 0) ! 996: return p->offset; ! 997: return -1; ! 998: } ! 999: ! 1000: ! 1001: static struct bufpool { ! 1002: struct bufpool *next; ! 1003: char buf[1]; /* variable size */ ! 1004: } *bufpool = NULL; ! 1005: ! 1006: /* ! 1007: * allocate buffer, all buffers allocated with this function can be ! 1008: * freed with one call to freebufpool() ! 1009: */ ! 1010: static VOID * ! 1011: allocbuf(int size) ! 1012: { ! 1013: struct bufpool *p; ! 1014: ! 1015: p = xmalloc(size + sizeof(struct bufpool *)); ! 1016: p->next = bufpool; ! 1017: bufpool = p; ! 1018: return p->buf; ! 1019: } ! 1020: ! 1021: /* ! 1022: * free all memory obtained with allocbuf() ! 1023: */ ! 1024: static void freebufpool(void) ! 1025: { ! 1026: struct bufpool *p; ! 1027: ! 1028: while (bufpool) { ! 1029: p = bufpool; ! 1030: bufpool = bufpool->next; ! 1031: free(p); ! 1032: } ! 1033: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.