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