|
|
1.1.1.9 ! root 1: /* keymgmt.c - Key management 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 <ctype.h> ! 29: #include "system.h" ! 30: #include "mpilib.h" ! 31: #include "random.h" ! 32: #include "crypto.h" ! 33: #include "fileio.h" ! 34: #include "keymgmt.h" ! 35: #include "rsagen.h" ! 36: #include "mpiio.h" ! 37: #include "language.h" ! 38: #include "pgp.h" ! 39: #include "md5.h" ! 40: #include "charset.h" ! 41: #include "keymaint.h" ! 42: #include "idea.h" ! 43: #ifdef MACTC5 ! 44: #include "Aestuff.h" ! 45: #include "MacPGP.h" ! 46: #include "Macutil2.h" ! 47: #include "Macutil3.h" ! 48: #include "PGPDialogs.h" ! 49: #include "password.h" ! 50: #include "exitpgp.h" ! 51: #include "MyBufferedStdio.h" ! 52: #include "ReplaceStdio.h" ! 53: boolean userid_match(char *userid, char *substr,unitptr n); ! 54: void showKeyHash( unitptr n, unitptr e ); ! 55: int backup_rename(char *scratchfile, char *destfile); ! 56: #endif ! 57: ! 58: /* ! 59: ** Convert to or from external byte order. ! 60: ** Note that convert_byteorder does nothing if the external byteorder ! 61: ** is the same as the internal byteorder. ! 62: */ ! 63: #define convert2(x,lx) convert_byteorder( (byteptr)&(x), (lx) ) ! 64: #define convert(x) convert2( (x), sizeof(x) ) ! 65: ! 66: ! 67: /* ! 68: * check if userid matches the substring, magic characters ^ and $ ! 69: * can be used to match start and end of userid. ! 70: * if n is NULL, only return TRUE if substr is an exact match of ! 71: * userid, a substring does not match in this case. ! 72: * the comparison is always case insensitive ! 73: */ ! 74: #ifdef MACTC5 ! 75: boolean userid_match(char *userid, char *substr, unitptr n) ! 76: #else ! 77: static boolean userid_match(char *userid, char *substr, unitptr n) ! 78: #endif ! 79: { ! 80: boolean match_end = FALSE; ! 81: int id_len, sub_len, i; ! 82: char buf[256], sub[256], *p; ! 83: #ifdef MACTC5 ! 84: int j; ! 85: char argKeyID[10],curKeyID[10]; ! 86: unsigned long tempKeyID[2]; ! 87: #endif ! 88: ! 89: if (substr == NULL || *substr == '\0') ! 90: return TRUE; ! 91: if (userid == NULL || *userid == '\0') ! 92: return FALSE; ! 93: ! 94: /* Check whether we have an ASCII or hex userID to check for */ ! 95: #ifdef EBCDIC ! 96: /* EBCDIC assertion: to_lower works on EBCDIC (not internal) charset */ ! 97: if (n != NULL && EXT_C(substr[0]) == '0' && to_lower(EXT_C(substr[1])) == 'x') { ! 98: userid = key2IDstring(n); ! 99: CONVERT_TO_CANONICAL_CHARSET(userid); ! 100: substr += 2; ! 101: } ! 102: id_len = strlen(userid); ! 103: for (i = 0; i <= id_len; ++i) ! 104: buf[i] = INT_C(to_lower(EXT_C(userid[i]))); ! 105: ! 106: sub_len = strlen(substr); ! 107: for (i = 0; i <= sub_len; ++i) ! 108: sub[i] = INT_C(to_lower(EXT_C(substr[i]))); ! 109: #else /* !EBCDIC */ ! 110: if (n != NULL && substr[0] == '0' && to_lower(substr[1]) == 'x') { ! 111: userid = key2IDstring(n); ! 112: substr += 2; ! 113: } ! 114: id_len = strlen(userid); ! 115: for (i = 0; i <= id_len; ++i) ! 116: buf[i] = to_lower(userid[i]); ! 117: ! 118: sub_len = strlen(substr); ! 119: for (i = 0; i <= sub_len; ++i) ! 120: sub[i] = to_lower(substr[i]); ! 121: #endif /* !EBCDIC */ ! 122: ! 123: if (n == NULL) { ! 124: return !strcmp(buf, sub); ! 125: } ! 126: #ifdef MAGIC_MATCH ! 127: if (sub_len > 1 && sub[sub_len - 1] == '$') { ! 128: match_end = TRUE; ! 129: sub[--sub_len] = '\0'; ! 130: } ! 131: if (*sub == '^') { ! 132: if (match_end) ! 133: return !strcmp(buf, sub + 1); ! 134: else ! 135: return !strncmp(buf, sub + 1, sub_len - 1); ! 136: } ! 137: #endif ! 138: if (sub_len > id_len) ! 139: return FALSE; ! 140: ! 141: if (match_end) ! 142: return !strcmp(buf + id_len - sub_len, sub); ! 143: ! 144: p = buf; ! 145: while ((p = strchr(p, *sub)) != NULL) { ! 146: if (strncmp(p, sub, sub_len) == 0) ! 147: #ifdef MACTC5 ! 148: { if (!argc) ! 149: return true; ! 150: for(j=1; j<100; j++) { ! 151: if (argv[j]==nil) { ! 152: j=100; ! 153: break; ! 154: } ! 155: if (!strcmp(substr,argv[j])) break; ! 156: } ! 157: if (j==100) return TRUE; ! 158: if (arg_keyid[j]==0) return TRUE; ! 159: tempKeyID[0]=0; ! 160: tempKeyID[1]=arg_keyid[j]; ! 161: strcpy(argKeyID,keyIDstring((byte *)tempKeyID)); ! 162: strcpy(curKeyID,key2IDstring( n )); ! 163: if (strcmp(argKeyID,curKeyID)) ! 164: return FALSE; ! 165: else { ! 166: arg_keyid[j]=0; ! 167: return TRUE; ! 168: } ! 169: } ! 170: #else ! 171: return TRUE; ! 172: #endif ! 173: ++p; ! 174: } ! 175: return FALSE; ! 176: } ! 177: ! 178: int is_key_ctb(byte ctb) ! 179: { ! 180: return ctb == CTB_CERT_PUBKEY || ctb == CTB_CERT_SECKEY; ! 181: } ! 182: ! 183: ! 184: /* ! 185: ** keyIDstring ! 186: ** ! 187: ** Return printable key fragment, which is an abbreviation of the public ! 188: ** key. Show LEAST significant 32 bits (KEYFRAGSIZE bytes) of modulus, ! 189: ** LSB last. Yes, that's LSB LAST. ! 190: */ ! 191: ! 192: char const blankkeyID[] = " "; ! 193: ! 194: char *keyIDstring(byte * keyID) ! 195: { ! 196: short i; ! 197: char *bufptr; /* ptr to Key ID string */ ! 198: static char keyIDbuf[9]; ! 199: ! 200: /* only show bottom 4 bytes of keyID */ ! 201: ! 202: bufptr = keyIDbuf; ! 203: ! 204: #ifdef XLOWFIRST ! 205: /* LSB-first keyID format */ ! 206: ! 207: for (i = 3; i >= 0; i--) { ! 208: sprintf(bufptr, "%02X", keyID[i]); ! 209: bufptr += 2; ! 210: } ! 211: #else ! 212: /* MSB-first keyID format */ ! 213: ! 214: for (i = KEYFRAGSIZE - 4; i < KEYFRAGSIZE; i++) { ! 215: sprintf(bufptr, "%02X", keyID[i]); ! 216: bufptr += 2; ! 217: } ! 218: #endif ! 219: *bufptr = '\0'; ! 220: return keyIDbuf; ! 221: } /* keyIDstring */ ! 222: ! 223: ! 224: ! 225: void extract_keyID(byteptr keyID, unitptr n) ! 226: /* ! 227: * Extract key fragment from modulus n. keyID byte array must be ! 228: * at least KEYFRAGSIZE bytes long. ! 229: */ ! 230: { ! 231: byte buf[MAX_BYTE_PRECISION + 2]; ! 232: short i, j; ! 233: ! 234: fill0(buf, KEYFRAGSIZE + 2); /* in case n is too short */ ! 235: reg2mpi(buf, n); /* MUST be at least KEYFRAGSIZE long */ ! 236: #ifdef XLOWFIRST ! 237: i = reg2mpi(buf, n); /* MUST be at least KEYFRAGSIZE long */ ! 238: /* For LSB-first keyID format, start of keyID is: */ ! 239: i = 2; /* skip over the 2 bytes of bitcount */ ! 240: for (j = 0; j < KEYFRAGSIZE;) ! 241: keyID[j++] = buf[i++]; ! 242: #else ! 243: i = reg2mpi(buf, n); /* MUST be at least KEYFRAGSIZE long */ ! 244: /* For MSB-first keyID format, start of keyID is: */ ! 245: i = i + 2 - KEYFRAGSIZE; ! 246: for (j = 0; j < KEYFRAGSIZE;) ! 247: keyID[j++] = buf[i++]; ! 248: #endif ! 249: ! 250: } /* extract_keyID */ ! 251: ! 252: ! 253: ! 254: char *key2IDstring(unitptr n) ! 255: /* Derive the key abbreviation fragment from the modulus n, ! 256: and return printable string of key ID. ! 257: n is key modulus from which to extract keyID. ! 258: */ ! 259: { ! 260: byte keyID[KEYFRAGSIZE]; ! 261: extract_keyID(keyID, n); ! 262: return keyIDstring(keyID); ! 263: } /* key2IDstring */ ! 264: ! 265: ! 266: ! 267: static void showkeyID(byteptr keyID, FILE *pgpout) ! 268: /* Print key fragment, which is an abbreviation of the public key. */ ! 269: { ! 270: fprintf(pgpout, "%s", keyIDstring(keyID)); ! 271: } /* showkeyID */ ! 272: ! 273: ! 274: ! 275: void writekeyID(unitptr n, FILE * f) ! 276: /* Write message prefix keyID to a file. ! 277: n is key modulus from which to extract keyID. ! 278: */ ! 279: { ! 280: byte keyID[KEYFRAGSIZE]; ! 281: extract_keyID(keyID, n); ! 282: fwrite(keyID, 1, KEYFRAGSIZE, f); ! 283: } /* writekeyID */ ! 284: ! 285: ! 286: ! 287: static boolean checkkeyID(byte * keyID, unitptr n) ! 288: /* Compare specified keyID with one derived from actual key modulus n. */ ! 289: { ! 290: byte keyID0[KEYFRAGSIZE]; ! 291: if (keyID == NULL) /* no key ID -- assume a good match */ ! 292: return TRUE; ! 293: extract_keyID(keyID0, n); ! 294: return equal_buffers(keyID, keyID0, KEYFRAGSIZE); ! 295: } /* checkkeyID */ ! 296: ! 297: ! 298: ! 299: /* external function prototype, from mpiio.c */ ! 300: void dump_unit_array(string s, unitptr r); ! 301: ! 302: void write_trust(FILE * f, byte trustbyte) ! 303: /* Write a key control packet to f, with the specified trustbyte data. ! 304: */ ! 305: { ! 306: putc(CTB_KEYCTRL, f); /* Key control header byte */ ! 307: putc(1, f); /* Key control length */ ! 308: putc(trustbyte, f); /* Key control byte */ ! 309: } ! 310: ! 311: static ! 312: short writekeyfile(char *fname, struct IdeaCfbContext *cfb, word32 timestamp, ! 313: byte * userid, unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, ! 314: unitptr u) ! 315: /* Write key components p, q, n, e, d, and u to specified file. ! 316: hidekey is TRUE iff key should be encrypted. ! 317: userid is a length-prefixed Pascal-type character string. ! 318: We write three packets: a key packet, a key control packet, and ! 319: a userid packet. We assume the key being written is our own, ! 320: so we set the control bits for full trust. ! 321: */ ! 322: { ! 323: FILE *f; ! 324: byte ctb; ! 325: byte alg, version; ! 326: word16 validity; ! 327: word16 cert_length; ! 328: extern word16 mpi_checksum; ! 329: byte iv[8]; ! 330: int i; ! 331: ! 332: /* open file f for write, in binary (not text) mode... */ ! 333: if ((f = fopen(fname, FOPWBIN)) == NULL) { ! 334: fprintf(pgpout, ! 335: LANG("\n\007Unable to create key file '%s'.\n"), fname); ! 336: return -1; ! 337: } ! 338: /*** Begin key certificate header fields ***/ ! 339: if (d == NULL) { ! 340: /* public key certificate */ ! 341: ctb = CTB_CERT_PUBKEY; ! 342: cert_length = 1 + SIZEOF_TIMESTAMP + 2 + 1 + (countbytes(n) + 2) ! 343: + (countbytes(e) + 2); ! 344: } else { ! 345: /* secret key certificate */ ! 346: ctb = CTB_CERT_SECKEY; ! 347: cert_length = 1 + SIZEOF_TIMESTAMP + 2 + 1 ! 348: + (countbytes(n) + 2) ! 349: + (countbytes(e) + 2) ! 350: + 1 + (cfb ? 8 : 0) /* IDEA algorithm byte and IV */ ! 351: +(countbytes(d) + 2) ! 352: + (countbytes(p) + 2) + (countbytes(q) + 2) ! 353: + (countbytes(u) + 2) + 2; ! 354: ! 355: } ! 356: ! 357: fwrite(&ctb, 1, 1, f); /* write key certificate header byte */ ! 358: convert(cert_length); /* convert to external byteorder */ ! 359: fwrite(&cert_length, 1, sizeof(cert_length), f); ! 360: version = version_byte; ! 361: fwrite(&version, 1, 1, f); /* set version number */ ! 362: memcpy(iv, ×tamp, 4); ! 363: convert_byteorder(iv, 4); /* convert to external form */ ! 364: fwrite(iv, 1, 4, f); /* write certificate timestamp */ ! 365: validity = 0; ! 366: fwrite(&validity, 1, sizeof(validity), f); /* validity period */ ! 367: alg = RSA_ALGORITHM_BYTE; ! 368: fwrite(&alg, 1, 1, f); ! 369: write_mpi(n, f, FALSE); ! 370: write_mpi(e, f, FALSE); ! 371: ! 372: if (is_secret_key(ctb)) { /* secret key */ ! 373: /* Write byte for following algorithm */ ! 374: alg = cfb ? IDEA_ALGORITHM_BYTE : 0; ! 375: putc(alg, f); ! 376: ! 377: if (cfb) { /* store encrypted IV */ ! 378: for (i = 0; i < 8; i++) ! 379: iv[i] = trueRandByte(); ! 380: ideaCfbEncrypt(cfb, iv, iv, 8); ! 381: fwrite(iv, 1, 8, f); /* write out the IV */ ! 382: } ! 383: mpi_checksum = 0; ! 384: write_mpi(d, f, cfb); ! 385: write_mpi(p, f, cfb); ! 386: write_mpi(q, f, cfb); ! 387: write_mpi(u, f, cfb); ! 388: /* Write checksum here - based on plaintext values */ ! 389: convert(mpi_checksum); ! 390: fwrite(&mpi_checksum, 1, sizeof(mpi_checksum), f); ! 391: } else { ! 392: /* Keyring control packet, public keys only */ ! 393: write_trust(f, KC_OWNERTRUST_ULTIMATE | KC_BUCKSTOP); ! 394: } ! 395: /* User ID packet */ ! 396: ctb = CTB_USERID; ! 397: fwrite(&ctb, 1, 1, f); /* write userid header byte */ ! 398: fwrite(userid, 1, userid[0] + 1, f); /* write user ID */ ! 399: if (d == NULL) /* only on public keyring */ ! 400: write_trust(f, KC_LEGIT_COMPLETE); ! 401: if (write_error(f)) { ! 402: fclose(f); ! 403: return -1; ! 404: } ! 405: fclose(f); ! 406: if (verbose) ! 407: fprintf(pgpout, "%d-bit %s key written to file '%s'.\n", ! 408: countbits(n), ! 409: is_secret_key(ctb) ? "secret" : "public", ! 410: fname); ! 411: return 0; ! 412: } /* writekeyfile */ ! 413: ! 414: #ifdef EBCDIC ! 415: /* in RECFM=FB datasets fread() != 0 when eof() cause of padding 0x00 */ ! 416: #define CTB_EOF 0x00 ! 417: #else ! 418: #define CTB_EOF 0x1A ! 419: #endif ! 420: ! 421: /* Return -1 on EOF, else read next key packet, return its ctb, and ! 422: * advance pointer to beyond the packet. ! 423: * This is short of a "short form" of readkeypacket ! 424: */ ! 425: short nextkeypacket(FILE * f, byte * pctb) ! 426: { ! 427: word32 cert_length; ! 428: int count; ! 429: byte ctb; ! 430: ! 431: *pctb = 0; /* assume no ctb for caller at first */ ! 432: count = fread(&ctb, 1, 1, f); /* read key certificate CTB byte */ ! 433: if (count == 0) ! 434: return -1; /* premature eof */ ! 435: *pctb = ctb; /* returns type to caller */ ! 436: if ((ctb != CTB_CERT_PUBKEY) && (ctb != CTB_CERT_SECKEY) && ! 437: (ctb != CTB_USERID) && (ctb != CTB_KEYCTRL) && ! 438: !is_ctb_type(ctb, CTB_SKE_TYPE) && ! 439: !is_ctb_type(ctb, CTB_COMMENT_TYPE)) ! 440: /* Either bad key packet or X/Ymodem padding detected */ ! 441: return (ctb == CTB_EOF) ? -1 : -2; ! 442: ! 443: cert_length = getpastlength(ctb, f); /* read certificate length */ ! 444: ! 445: if (cert_length > MAX_KEYCERT_LENGTH - 3) ! 446: return -3; /* bad length */ ! 447: ! 448: fseek(f, cert_length, SEEK_CUR); ! 449: return 0; ! 450: } /* nextkeypacket */ ! 451: ! 452: /* ! 453: * Reads a key certificate from the current file position of file f. ! 454: * Depending on the certificate type, it will set the proper fields ! 455: * of the return arguments. Other fields will not be set. ! 456: * pctb is always set. ! 457: * If the packet is CTB_CERT_PUBKEY or CTB_CERT_SECKEY, it will ! 458: * return timestamp, n, e, and if the secret key components are ! 459: * present and d is not NULL, it will read, decrypt if hidekey is ! 460: * true, and return d, p, q, and u. ! 461: * If the packet is CTB_KEYCTRL, it will return keyctrl as that byte. ! 462: * If the packet is CTB_USERID, it will return userid. ! 463: * If the packet is CTB_COMMENT_TYPE, it won't return anything extra. ! 464: * The file pointer is left positioned after the certificate. ! 465: * ! 466: * If the key could not be read because of a version error or bad ! 467: * data, the return value is -6 or -4, the file pointer will be ! 468: * positioned after the certificate, only the arguments pctb and ! 469: * userid will valid in this case, other arguments are undefined. ! 470: * Return value -3 means the error is unrecoverable. ! 471: */ ! 472: short readkeypacket(FILE * f, struct IdeaCfbContext *cfb, byte * pctb, ! 473: byte * timestamp, char *userid, ! 474: unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u, ! 475: byte * sigkeyID, byte * keyctrl) ! 476: { ! 477: byte ctb; ! 478: word16 cert_length; ! 479: int count; ! 480: byte version, alg, mdlen; ! 481: word16 validity; ! 482: word16 chksum; ! 483: extern word16 mpi_checksum; ! 484: long next_packet; ! 485: byte iv[8]; ! 486: ! 487: /*** Begin certificate header fields ***/ ! 488: *pctb = 0; /* assume no ctb for caller at first */ ! 489: count = fread(&ctb, 1, 1, f); /* read key certificate CTB byte */ ! 490: if (count == 0) ! 491: return -1; /* premature eof */ ! 492: *pctb = ctb; /* returns type to caller */ ! 493: if ((ctb != CTB_CERT_PUBKEY) && (ctb != CTB_CERT_SECKEY) && ! 494: (ctb != CTB_USERID) && (ctb != CTB_KEYCTRL) && ! 495: !is_ctb_type(ctb, CTB_SKE_TYPE) && ! 496: !is_ctb_type(ctb, CTB_COMMENT_TYPE)) ! 497: /* Either bad key packet or X/Ymodem padding detected */ ! 498: return (ctb == CTB_EOF) ? -1 : -2; ! 499: ! 500: cert_length = getpastlength(ctb, f); /* read certificate length */ ! 501: ! 502: if (cert_length > MAX_KEYCERT_LENGTH - 3) ! 503: return -3; /* bad length */ ! 504: ! 505: next_packet = ftell(f) + cert_length; ! 506: ! 507: /* ! 508: * skip packet and return, keeps us in sync when we hit a ! 509: * version error or bad data. Implemented oddly to make it ! 510: * only one statement. ! 511: */ ! 512: #define SKIP_RETURN(x) return fseek(f, next_packet, SEEK_SET), x ! 513: ! 514: if (ctb == CTB_USERID) { ! 515: if (cert_length > 255) ! 516: return -3; /* Bad length error */ ! 517: if (userid) { ! 518: userid[0] = cert_length; /* Save user ID length */ ! 519: fread(userid + 1, 1, cert_length, f); /* read rest of user ID */ ! 520: } else ! 521: fseek(f, (long) cert_length, SEEK_CUR); ! 522: return 0; /* normal return */ ! 523: ! 524: } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 525: ! 526: if (sigkeyID) { ! 527: fread(&version, 1, 1, f); /* Read version of sig packet */ ! 528: if (version_byte_error(version)) ! 529: SKIP_RETURN(-6); /* Need a later version */ ! 530: /* Skip timestamp, validity period, and type byte */ ! 531: fread(&mdlen, 1, 1, f); ! 532: fseek(f, (long) mdlen, SEEK_CUR); ! 533: /* Read and return KEY ID */ ! 534: fread(sigkeyID, 1, KEYFRAGSIZE, f); ! 535: } ! 536: SKIP_RETURN(0); /* normal return */ ! 537: ! 538: } else if (ctb == CTB_KEYCTRL) { ! 539: ! 540: if (cert_length != 1) ! 541: return -3; /* Bad length error */ ! 542: if (keyctrl) ! 543: fread(keyctrl, 1, cert_length, f); /* Read key control byte */ ! 544: else ! 545: fseek(f, (long) cert_length, SEEK_CUR); ! 546: return 0; /* normal return */ ! 547: ! 548: } else if (!is_key_ctb(ctb)) /* comment or other packet */ ! 549: SKIP_RETURN(0); /* normal return */ ! 550: ! 551: /* Here we have a key packet */ ! 552: if (n != NULL) ! 553: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */ ! 554: fread(&version, 1, 1, f); /* read and check version */ ! 555: if (version_byte_error(version)) ! 556: SKIP_RETURN(-6); /* Need a later version */ ! 557: if (timestamp) { ! 558: fread(timestamp, 1, SIZEOF_TIMESTAMP, f); /* read certificate ! 559: timestamp */ ! 560: convert_byteorder(timestamp, SIZEOF_TIMESTAMP); /* convert from ! 561: external form */ ! 562: } else { ! 563: fseek(f, (long) SIZEOF_TIMESTAMP, SEEK_CUR); ! 564: } ! 565: fread(&validity, 1, sizeof(validity), f); /* Read validity period */ ! 566: convert(validity); /* convert from external byteorder */ ! 567: /* We don't use validity period yet */ ! 568: fread(&alg, 1, 1, f); ! 569: if (version_error(alg, RSA_ALGORITHM_BYTE)) ! 570: SKIP_RETURN(-6); /* Need a later version */ ! 571: /*** End certificate header fields ***/ ! 572: ! 573: /* We're past certificate headers, now look at some key material... */ ! 574: ! 575: cert_length -= 1 + SIZEOF_TIMESTAMP + 2 + 1; ! 576: ! 577: if (n == NULL) /* Skip key certificate data */ ! 578: SKIP_RETURN(0); ! 579: ! 580: if (read_mpi(n, f, TRUE, FALSE) < 0) ! 581: SKIP_RETURN(-4); /* data corrupted, return error */ ! 582: ! 583: /* Note that precision was adjusted for n */ ! 584: ! 585: if (read_mpi(e, f, FALSE, FALSE) < 0) ! 586: SKIP_RETURN(-4); /* data corrupted, error return */ ! 587: ! 588: cert_length -= (countbytes(n) + 2) + (countbytes(e) + 2); ! 589: ! 590: if (d == NULL) { /* skip rest of this key certificate */ ! 591: if (cert_length && !is_secret_key(ctb)) ! 592: SKIP_RETURN(-4); /* key w/o userID */ ! 593: else ! 594: SKIP_RETURN(0); /* Normal return */ ! 595: } ! 596: ! 597: if (is_secret_key(ctb)) { ! 598: fread(&alg, 1, 1, f); ! 599: if (alg && version_error(alg, IDEA_ALGORITHM_BYTE)) ! 600: SKIP_RETURN(-6); /* Unknown version */ ! 601: ! 602: if (!cfb && alg) ! 603: /* Don't bother trying if hidekey is false and alg is true */ ! 604: SKIP_RETURN(-5); ! 605: ! 606: if (alg) { /* if secret components are encrypted... */ ! 607: /* process encrypted CFB IV before reading secret components */ ! 608: count = fread(iv, 1, 8, f); ! 609: if (count < 8) ! 610: return -4; /* data corrupted, error return */ ! 611: ! 612: ideaCfbDecrypt(cfb, iv, iv, 8); ! 613: cert_length -= 8; /* take IV length into account */ ! 614: } ! 615: /* Reset checksum before these reads */ ! 616: mpi_checksum = 0; ! 617: ! 618: if (read_mpi(d, f, FALSE, cfb) < 0) ! 619: return -4; /* data corrupted, error return */ ! 620: if (read_mpi(p, f, FALSE, cfb) < 0) ! 621: return -4; /* data corrupted, error return */ ! 622: if (read_mpi(q, f, FALSE, cfb) < 0) ! 623: return -4; /* data corrupted, error return */ ! 624: ! 625: /* use register 'u' briefly as scratchpad */ ! 626: mp_mult(u, p, q); /* compare p*q against n */ ! 627: if (mp_compare(n, u) != 0) /* bad pass phrase? */ ! 628: return -5; /* possible bad pass phrase, error return */ ! 629: /* now read in real u */ ! 630: if (read_mpi(u, f, FALSE, cfb) < 0) ! 631: return -4; /* data corrupted, error return */ ! 632: ! 633: /* Read checksum, compare with mpi_checksum */ ! 634: fread(&chksum, 1, sizeof(chksum), f); ! 635: convert(chksum); ! 636: if (chksum != mpi_checksum) ! 637: return -5; /* possible bad pass phrase */ ! 638: ! 639: cert_length -= 1 + (countbytes(d) + 2) + (countbytes(p) + 2) ! 640: + (countbytes(q) + 2) + (countbytes(u) + 2) + 2; ! 641: ! 642: } else { /* not a secret key */ ! 643: ! 644: mp_init(d, 0); ! 645: mp_init(p, 0); ! 646: mp_init(q, 0); ! 647: mp_init(u, 0); ! 648: } ! 649: ! 650: if (cert_length != 0) { ! 651: fprintf(pgpout, "\n\007Corrupted key. Bad length, off by %d bytes.\n", ! 652: (int) cert_length); ! 653: SKIP_RETURN(-4); /* data corrupted, error return */ ! 654: } ! 655: return 0; /* normal return */ ! 656: ! 657: } /* readkeypacket */ ! 658: ! 659: /* ! 660: * keyID contains key fragment we expect to find in keyfile. ! 661: * If keyID is NULL, then userid contains a C string search target of ! 662: * userid to find in keyfile. ! 663: * keyfile is the file to begin search in, and it may be modified ! 664: * to indicate true filename of where the key was found. It can be ! 665: * either a public key file or a secret key file. ! 666: * file_position is returned as the byte offset within the keyfile ! 667: * that the key was found at. pktlen is the length of the key packet. ! 668: * These values are for the key packet itself, not including any ! 669: * following userid, control, signature, or comment packets. ! 670: * ! 671: * possible flags: ! 672: * GPK_GIVEUP: we are just going to do a single file search only. ! 673: * GPK_SHOW: show the key if found. ! 674: * GPK_NORVK: skip revoked keys. ! 675: * GPK_DISABLED: don't ignore disabled keys (when doing userid lookup) ! 676: * GPK_SECRET: looking for a secret key ! 677: * ! 678: * Returns -6 if the key was found but the key was not read because of a ! 679: * version error or bad data. The arguments timestamp, n and e are ! 680: * undefined in this case. ! 681: */ ! 682: int getpublickey(int flags, char *keyfile, long *_file_position, ! 683: int *_pktlen, byte * keyID, byte * timestamp, byte * userid, ! 684: unitptr n, unitptr e) ! 685: { ! 686: byte ctb; /* returned by readkeypacket */ ! 687: FILE *f; ! 688: int status, keystatus = -1; ! 689: boolean keyfound = FALSE; ! 690: char matchid[256]; /* C string format */ ! 691: long fpos; ! 692: long file_position = 0; ! 693: int pktlen = 0; ! 694: boolean skip = FALSE; /* if TRUE: skip until next key packet */ ! 695: byte keyctrl; ! 696: #ifdef MACTC5 ! 697: boolean use_pubring2; ! 698: use_pubring2 = (globalPubringName2[0] != '\0'); ! 699: #endif ! 700: ! 701: if (keyID == NULL) /* then userid has search target */ ! 702: strcpy(matchid, (char *) userid); ! 703: else ! 704: matchid[0] = '\0'; ! 705: ! 706: top: ! 707: if (strlen(keyfile) == 0) /* null filename */ ! 708: return -1; /* give up, error return */ ! 709: ! 710: if (!file_exists(keyfile)) ! 711: default_extension(keyfile, PGP_EXTENSION); ! 712: ! 713: if (!file_exists(keyfile)) { ! 714: if (flags & GPK_GIVEUP) ! 715: return -1; /* give up, error return */ ! 716: fprintf(pgpout, LANG("\n\007Keyring file '%s' does not exist. "), ! 717: keyfile); ! 718: fprintf(pgpout, "\n"); ! 719: goto nogood; ! 720: } ! 721: if (verbose) { ! 722: fprintf(pgpout, "searching key ring file '%s' ", keyfile); ! 723: if (keyID) ! 724: fprintf(pgpout, "for keyID %s\n", keyIDstring(keyID)); ! 725: else ! 726: fprintf(pgpout, "for userid \"%s\"\n", LOCAL_CHARSET(userid)); ! 727: } ! 728: /* open file f for read, in binary (not text) mode... */ ! 729: if ((f = fopen(keyfile, FOPRBIN)) == NULL) ! 730: return -1; /* error return */ ! 731: ! 732: keyfound = FALSE; ! 733: for (;;) { ! 734: fpos = ftell(f); ! 735: status = readkeypacket(f, FALSE, &ctb, timestamp, (char *) userid, ! 736: n, e, NULL, NULL, NULL, NULL, NULL, NULL); ! 737: /* Note that readkeypacket has called set_precision */ ! 738: ! 739: if (status == -1) /* end of file */ ! 740: break; ! 741: ! 742: if (status < -1 && status != -4 && status != -6) { ! 743: fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"), ! 744: keyfile); ! 745: fclose(f); /* close key file */ ! 746: return status; ! 747: } ! 748: /* Remember packet position and size for last key packet */ ! 749: if (is_key_ctb(ctb)) { ! 750: file_position = fpos; ! 751: pktlen = (int) (ftell(f) - fpos); ! 752: keystatus = status; ! 753: if (!keyID && !(flags & GPK_DISABLED) && ! 754: (is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE) || ! 755: is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) && ! 756: read_trust(f, &keyctrl) == 0 && ! 757: (keyctrl & KC_DISABLED)) ! 758: skip = TRUE; ! 759: else ! 760: skip = FALSE; ! 761: } ! 762: /* Only check for matches when we find a USERID packet */ ! 763: if (!skip && ctb == CTB_USERID) { ! 764: #ifdef MACTC5 ! 765: mac_poll_for_break(); ! 766: #endif ! 767: /* keyID contains key fragment. Check it against n from keyfile. */ ! 768: if (keyID != NULL) { ! 769: if (keystatus == 0) ! 770: keyfound = checkkeyID(keyID, n); ! 771: } else { ! 772: /* matchid is already a C string */ ! 773: PascalToC((char *) userid); /* for C string functions */ ! 774: /* Accept any matching subset */ ! 775: keyfound = userid_match((char *) userid, matchid, n); ! 776: CToPascal((char *) userid); ! 777: } ! 778: } ! 779: if (keyfound) { ! 780: if (flags & GPK_SHOW) ! 781: show_key(f, file_position, 0); ! 782: fseek(f, file_position, SEEK_SET); ! 783: if ((flags & GPK_NORVK) && keystatus == 0 && is_compromised(f)) { ! 784: if (flags & GPK_SHOW) { /* already printed user ID */ ! 785: fprintf(pgpout, ! 786: LANG("\n\007Sorry, this key has been revoked by its owner.\n")); ! 787: } else { ! 788: PascalToC((char *) userid); ! 789: fprintf(pgpout, LANG("\nKey for user ID \"%s\"\n\ ! 790: has been revoked. You cannot use this key.\n"), ! 791: LOCAL_CHARSET((char *) userid)); ! 792: } ! 793: keyfound = FALSE; ! 794: skip = TRUE; ! 795: /* we're positioned at the key packet, skip it */ ! 796: nextkeypacket(f, &ctb); ! 797: } else { ! 798: /* found key, normal return */ ! 799: if (_pktlen) ! 800: *_pktlen = pktlen; ! 801: if (_file_position) ! 802: *_file_position = file_position; ! 803: fclose(f); ! 804: return keystatus; ! 805: } ! 806: } ! 807: } /* while TRUE */ ! 808: ! 809: fclose(f); /* close key file */ ! 810: ! 811: if (flags & GPK_GIVEUP) ! 812: return -1; /* give up, error return */ ! 813: ! 814: if (keyID != NULL) { ! 815: fprintf(pgpout, ! 816: LANG("\n\007Key matching expected Key ID %s not found in file '%s'.\n"), ! 817: keyIDstring(keyID), keyfile); ! 818: } else { ! 819: fprintf(pgpout, ! 820: LANG("\n\007Key matching userid '%s' not found in file '%s'.\n"), ! 821: LOCAL_CHARSET(matchid), keyfile); ! 822: } ! 823: ! 824: nogood: ! 825: if (filter_mode || batchmode) ! 826: return -1; /* give up, error return */ ! 827: ! 828: #ifdef MACTC5 ! 829: { ! 830: Boolean result; ! 831: if (flags & GPK_SECRET) ! 832: result=GetFilePath(LANG("Enter secret key filename: "), keyfile, GETFILE); ! 833: else if (use_pubring2) { ! 834: strcpy(keyfile,globalPubringName2); ! 835: use_pubring2 = false; ! 836: result = true; ! 837: } else ! 838: result=GetFilePath(LANG("Enter public key filename: "), keyfile, GETFILE); ! 839: if (!result) strcpy(keyfile,""); ! 840: if (flags & GPK_SECRET) ! 841: fprintf(pgpout,LANG("Enter secret key filename: ")); ! 842: else ! 843: fprintf(pgpout,LANG("Enter public key filename: ")); ! 844: fprintf(pgpout, "%s\n",keyfile); ! 845: } ! 846: #else ! 847: if (flags & GPK_SECRET) ! 848: fprintf(pgpout, LANG("Enter secret key filename: ")); ! 849: else ! 850: fprintf(pgpout, LANG("Enter public key filename: ")); ! 851: ! 852: getstring(keyfile, 59, TRUE); /* echo keyboard input */ ! 853: #endif ! 854: goto top; ! 855: ! 856: } /* getpublickey */ ! 857: ! 858: /* Start at key_position in keyfile, and scan for the key packet ! 859: that contains userid. Return userid_position and userid_len. ! 860: Return 0 if OK, -1 on error. Userid should be a C string. ! 861: If exact_match is TRUE, the userid must match for full length, ! 862: a substring is not enough. ! 863: */ ! 864: int getpubuserid(char *keyfile, long key_position, byte * userid, ! 865: long *userid_position, int *userid_len, boolean exact_match) ! 866: { ! 867: unit n[MAX_UNIT_PRECISION]; ! 868: unit e[MAX_UNIT_PRECISION]; ! 869: byte ctb; /* returned by readkeypacket */ ! 870: FILE *f; ! 871: int status; ! 872: char userid0[256]; /* C string format */ ! 873: long fpos; ! 874: ! 875: /* open file f for read, in binary (not text) mode... */ ! 876: if ((f = fopen(keyfile, FOPRBIN)) == NULL) ! 877: return -1; /* error return */ ! 878: ! 879: /* Start off at correct location */ ! 880: fseek(f, key_position, SEEK_SET); ! 881: (void) nextkeypacket(f, &ctb); /* Skip key */ ! 882: for (;;) { ! 883: fpos = ftell(f); ! 884: status = readkeypacket(f, FALSE, &ctb, NULL, (char *) userid0, n, e, ! 885: NULL, NULL, NULL, NULL, NULL, NULL); ! 886: ! 887: if (status < 0 || is_key_ctb(ctb)) { ! 888: fclose(f); /* close key file */ ! 889: return status ? status : -1; /* give up, error return */ ! 890: } ! 891: /* Only check for matches when we find a USERID packet */ ! 892: if (ctb == CTB_USERID) { ! 893: if (userid[0] == '0' && userid[1] == 'x') ! 894: break; /* use first userid if user specified a keyID */ ! 895: /* userid is already a C string */ ! 896: PascalToC((char *) userid0); /* for C string functions */ ! 897: /* Accept any matching subset if exact_match is FALSE */ ! 898: if (userid_match((char *) userid0, (char *) userid, ! 899: (exact_match ? NULL : n))) ! 900: break; ! 901: } ! 902: } /* for(;;) */ ! 903: *userid_position = fpos; ! 904: *userid_len = (int) (ftell(f) - fpos); ! 905: fclose(f); ! 906: return 0; /* normal return */ ! 907: } /* getpubuserid */ ! 908: ! 909: /* ! 910: * Start at user_position in keyfile, and scan for the signature packet ! 911: * that matches sigkeyID. Return the signature timestamp, sig_position ! 912: * and sig_len. ! 913: * ! 914: * Return 0 if OK, -1 on error. ! 915: */ ! 916: int getpubusersig(char *keyfile, long user_position, byte * sigkeyID, ! 917: byte * timestamp, long *sig_position, int *sig_len) ! 918: { ! 919: byte ctb; /* returned by readkeypacket */ ! 920: FILE *f; ! 921: int status; ! 922: byte keyID0[KEYFRAGSIZE]; ! 923: long fpos; ! 924: ! 925: /* open file f for read, in binary (not text) mode... */ ! 926: if ((f = fopen(keyfile, FOPRBIN)) == NULL) ! 927: return -1; /* error return */ ! 928: ! 929: /* Start off at correct location */ ! 930: fseek(f, user_position, SEEK_SET); ! 931: (void) nextkeypacket(f, &ctb); /* Skip userid packet */ ! 932: for (;;) { ! 933: fpos = ftell(f); ! 934: status = readkeypacket(f, FALSE, &ctb, NULL, NULL, NULL, NULL, ! 935: NULL, NULL, NULL, NULL, keyID0, NULL); ! 936: ! 937: if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID) ! 938: break; ! 939: ! 940: /* Only check for matches when we find a signature packet */ ! 941: if (is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 942: if (equal_buffers(sigkeyID, keyID0, KEYFRAGSIZE)) { ! 943: *sig_position = fpos; ! 944: *sig_len = (int) (ftell(f) - fpos); ! 945: fseek(f, fpos + 6, SEEK_SET); ! 946: fread(timestamp, 1, SIZEOF_TIMESTAMP, f); /* read certificate ! 947: timestamp */ ! 948: convert_byteorder(timestamp, SIZEOF_TIMESTAMP); /* convert ! 949: from external ! 950: orm */ ! 951: fclose(f); ! 952: return 0; /* normal return */ ! 953: } ! 954: } ! 955: } /* for (;;) */ ! 956: ! 957: fclose(f); /* close key file */ ! 958: return status ? status : -1; /* give up, error return */ ! 959: } /* getpubusersig */ ! 960: ! 961: #ifdef MACTC5 ! 962: /* Truncated version of getsecretkey used to get default userid during ! 963: initialization. Does not annoy user by asking for password. */ ! 964: int getfirstsecretkey(boolean giveup, boolean showkey, char *keyfile, byte *keyID, ! 965: byte *timestamp, char *passp, boolean *hkey, ! 966: byte *userid, unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, ! 967: unitptr u) ! 968: { ! 969: char keyfilename[MAX_PATH]; /* for getpublickey */ ! 970: long file_position; ! 971: int pktlen; /* unused, just to satisfy getpublickey */ ! 972: ! 973: if (keyfile == NULL) ! 974: { /* use default pathname */ ! 975: buildfilename(keyfilename,globalSecringName); ! 976: keyfile = keyfilename; ! 977: } ! 978: ! 979: return(getpublickey(GPK_GIVEUP, keyfile, &file_position, &pktlen, ! 980: keyID, timestamp, userid, n, e)); ! 981: } ! 982: #endif ! 983: ! 984: /* ! 985: * keyID contains key fragment we expect to find in keyfile. ! 986: * If keyID is NULL, then userid contains search target of ! 987: * userid to find in keyfile. ! 988: * giveup controls whether we ask the user for the name of the ! 989: * secret key file on failure. showkey controls whether we print ! 990: * out the key information when we find it. keyfile, if non-NULL, ! 991: * is the name of the secret key file; if NULL, we use the ! 992: * default. hpass and hkey, if non-NULL, get returned with a copy ! 993: * of the hashed password buffer and hidekey variable. ! 994: */ ! 995: int getsecretkey(int flags, char *keyfile, byte * keyID, ! 996: byte * timestamp, byte * hpass, boolean * hkey, byte * userid, ! 997: unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, ! 998: unitptr u) ! 999: { ! 1000: byte ctb; /* returned by readkeypacket */ ! 1001: FILE *f; ! 1002: char keyfilename[MAX_PATH]; /* for getpublickey */ ! 1003: long file_position; ! 1004: int status; ! 1005: boolean hidekey; /* TRUE iff secret key is encrypted */ ! 1006: word16 iv[4]; /* initialization vector for encryption */ ! 1007: byte ideakey[16]; ! 1008: int guesses; ! 1009: struct hashedpw *hpw, **hpwp; ! 1010: struct IdeaCfbContext cfb; ! 1011: ! 1012: if (keyfile == NULL) { ! 1013: /* use default pathname */ ! 1014: strcpy(keyfilename, globalSecringName); ! 1015: keyfile = keyfilename; ! 1016: } ! 1017: status = getpublickey(flags | GPK_SECRET, keyfile, &file_position, ! 1018: NULL, keyID, timestamp, userid, n, e); ! 1019: if (status < 0) ! 1020: return status; /* error return */ ! 1021: ! 1022: /* open file f for read, in binary (not text) mode... */ ! 1023: if ((f = fopen(keyfile, FOPRBIN)) == NULL) ! 1024: return -1; /* error return */ ! 1025: ! 1026: /* First guess is no password */ ! 1027: hidekey = FALSE; ! 1028: fseek(f, file_position, SEEK_SET); /* reposition file to key */ ! 1029: status = readkeypacket(f, 0, &ctb, timestamp, (char *) userid, ! 1030: n, e, d, p, q, u, NULL, NULL); ! 1031: if (status != -5) /* Anything except bad password */ ! 1032: goto done; ! 1033: ! 1034: /* If we're not signing a key (when we force asking the user), ! 1035: * check the prevosuly known passwords. ! 1036: */ ! 1037: if (!(flags & GPK_ASKPASS)) { ! 1038: hidekey = TRUE; ! 1039: /* Then come existing key passwords */ ! 1040: hpw = keypasswds; ! 1041: while (hpw) { ! 1042: ideaCfbInit(&cfb, hpw->hash); ! 1043: fseek(f, file_position, SEEK_SET); ! 1044: status = readkeypacket(f, &cfb, &ctb, timestamp, ! 1045: (char *) userid, n, e, d, p, q, u, NULL, NULL); ! 1046: ideaCfbDestroy(&cfb); ! 1047: if (status != -5) { ! 1048: memcpy(ideakey, hpw->hash, sizeof(ideakey)); ! 1049: goto done; ! 1050: } ! 1051: hpw = hpw->next; ! 1052: } ! 1053: /* Then try "other" passwords" */ ! 1054: hpwp = &passwds; ! 1055: hpw = *hpwp; ! 1056: while (hpw) { ! 1057: ideaCfbInit(&cfb, hpw->hash); ! 1058: fseek(f, file_position, SEEK_SET); ! 1059: status = readkeypacket(f, &cfb, &ctb, timestamp, ! 1060: (char *) userid, n, e, d, p, q, u, NULL, NULL); ! 1061: ideaCfbDestroy(&cfb); ! 1062: if (status >= 0) { ! 1063: /* Success - move to key password list */ ! 1064: memcpy(ideakey, hpw->hash, sizeof(ideakey)); ! 1065: *hpwp = hpw->next; ! 1066: hpw->next = keypasswds; ! 1067: keypasswds = hpw; ! 1068: } ! 1069: if (status != -5) ! 1070: goto done; ! 1071: hpwp = &hpw->next; ! 1072: hpw = *hpwp; ! 1073: } ! 1074: } ! 1075: /* If batchmode, we don't ask the user. */ ! 1076: if (batchmode) { ! 1077: /* PGPPASS (or -z) wrong or not set */ ! 1078: fprintf(pgpout, LANG("\n\007Error: Bad pass phrase.\n")); ! 1079: fclose(f); /* close key file */ ! 1080: return -1; ! 1081: } ! 1082: /* Finally, prompt the user. */ ! 1083: fprintf(pgpout, ! 1084: LANG("\nYou need a pass phrase to unlock your RSA secret key. ")); ! 1085: if (!(flags & GPK_SHOW)) { ! 1086: /* let user know for which key he should type his password */ ! 1087: PascalToC((char *) userid); ! 1088: fprintf(pgpout, LANG("\nKey for user ID: %s\n"), ! 1089: LOCAL_CHARSET((char *) userid)); ! 1090: fprintf(pgpout, LANG("%d-bit key, key ID %s, created %s\n"), ! 1091: countbits(n), key2IDstring(n), cdate((word32 *) timestamp)); ! 1092: CToPascal((char *) userid); ! 1093: } ! 1094: guesses = 0; ! 1095: for (;;) { ! 1096: if (++guesses > 3) ! 1097: hidekey = 0; ! 1098: else ! 1099: hidekey = (GetHashedPassPhrase(ideakey, 1) > 0); ! 1100: /* ! 1101: * We've already tried the null password - interpret ! 1102: * a null string as "I dunno". ! 1103: */ ! 1104: if (!hidekey) { ! 1105: status = -5; /* Bad passphrase */ ! 1106: fputs(LANG("No passphrase; secret key unavailable.\n"), ! 1107: pgpout); ! 1108: break; ! 1109: } ! 1110: ideaCfbInit(&cfb, ideakey); ! 1111: fseek(f, file_position, SEEK_SET); ! 1112: status = readkeypacket(f, &cfb, &ctb, timestamp, ! 1113: (char *) userid, n, e, d, p, q, u, NULL, NULL); ! 1114: ideaCfbDestroy(&cfb); ! 1115: if (status >= 0) { ! 1116: #ifdef MACTC5 ! 1117: ; ! 1118: } ! 1119: if (Abort) guesses=1; ! 1120: #else ! 1121: /* Success - remember this key for later use */ ! 1122: if (flags & GPK_ASKPASS) { ! 1123: /* ! 1124: * This may be a duplicate because we didn't ! 1125: * search the lists before - check. ! 1126: */ ! 1127: hpw = passwds; ! 1128: while (hpw) { ! 1129: if (memcmp(hpw->hash, ideakey, ! 1130: sizeof(ideakey)) == 0) ! 1131: goto done; ! 1132: hpw = hpw->next; ! 1133: } ! 1134: hpw = keypasswds; ! 1135: while (hpw) { ! 1136: if (memcmp(hpw->hash, ideakey, ! 1137: sizeof(ideakey)) == 0) ! 1138: goto done; ! 1139: hpw = hpw->next; ! 1140: } ! 1141: } ! 1142: /* Insert new key into remember lists. */ ! 1143: hpw = (struct hashedpw *) malloc(sizeof(struct hashedpw)); ! 1144: if (hpw) { ! 1145: /* If malloc fails, just don't remember the phrase */ ! 1146: memcpy(hpw->hash, ideakey, sizeof(hpw->hash)); ! 1147: hpw->next = keypasswds; ! 1148: keypasswds = hpw; ! 1149: } ! 1150: } ! 1151: #endif /* MACTC5 */ ! 1152: if (status != -5) ! 1153: goto done; ! 1154: #ifdef MACTC5 ! 1155: passhash[0] = '\0'; ! 1156: #endif ! 1157: fprintf(pgpout, LANG("\n\007Error: Bad pass phrase.\n")); ! 1158: } ! 1159: while (--guesses); ! 1160: /* Failed - fall through to done */ ! 1161: ! 1162: done: ! 1163: fclose(f); ! 1164: if (hkey) ! 1165: *hkey = hidekey; ! 1166: if (status == -5) ! 1167: return status; ! 1168: if (status < 0) { ! 1169: fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"), ! 1170: keyfile); ! 1171: fclose(f); /* close key file */ ! 1172: return -1; ! 1173: } ! 1174: if (hpass) ! 1175: memcpy(hpass, ideakey, sizeof(ideakey)); ! 1176: burn(ideakey); ! 1177: ! 1178: /* Note that readkeypacket has called set_precision */ ! 1179: ! 1180: if (d != NULL) { /* No effective check of pass phrase if d is NULL */ ! 1181: if (!quietmode) { ! 1182: if (!hidekey) ! 1183: fprintf(pgpout, ! 1184: LANG("\nAdvisory warning: This RSA secret key is not protected by a \ ! 1185: passphrase.\n")); ! 1186: else ! 1187: fprintf(pgpout, LANG("Pass phrase is good. ")); ! 1188: } ! 1189: if (testeq(d, 0)) { /* didn't get secret key components */ ! 1190: fprintf(pgpout, ! 1191: LANG("\n\007Key file '%s' is not a secret key file.\n"), ! 1192: keyfile); ! 1193: return -1; ! 1194: } ! 1195: } ! 1196: return 0; /* normal return */ ! 1197: ! 1198: } /* getsecretkey */ ! 1199: ! 1200: /* ! 1201: * check if a key has a compromise certificate, file pointer must ! 1202: * be positioned at or right after the key packet. ! 1203: */ ! 1204: int is_compromised(FILE * f) ! 1205: { ! 1206: long pos, savepos; ! 1207: byte class, ctb; ! 1208: int cert_len; ! 1209: int status = 0; ! 1210: ! 1211: pos = savepos = ftell(f); ! 1212: ! 1213: nextkeypacket(f, &ctb); ! 1214: if (is_key_ctb(ctb)) { ! 1215: pos = ftell(f); ! 1216: nextkeypacket(f, &ctb); ! 1217: } ! 1218: if (ctb != CTB_KEYCTRL) ! 1219: fseek(f, pos, SEEK_SET); ! 1220: ! 1221: /* file pointer now positioned where compromise cert. should be */ ! 1222: if (fread(&ctb, 1, 1, f) != 1) { ! 1223: status = -1; ! 1224: goto ex; ! 1225: } ! 1226: if (is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 1227: cert_len = (int) getpastlength(ctb, f); ! 1228: if (cert_len > MAX_SIGCERT_LENGTH) { /* Huge packet length */ ! 1229: status = -1; ! 1230: goto ex; ! 1231: } ! 1232: /* skip version and mdlen byte */ ! 1233: fseek(f, 2L, SEEK_CUR); ! 1234: if (fread(&class, 1, 1, f) != 1) { ! 1235: status = -1; ! 1236: goto ex; ! 1237: } ! 1238: status = (class == KC_SIGNATURE_BYTE); ! 1239: } ! 1240: ex: ! 1241: fseek(f, savepos, SEEK_SET); ! 1242: return status; ! 1243: } ! 1244: ! 1245: ! 1246: /* Alfred Hitchcock coined the term "mcguffin" for the generic object ! 1247: being sought in his films-- the diamond, the microfilm, etc. ! 1248: */ ! 1249: ! 1250: ! 1251: /* ! 1252: * Calculate and display a hash for the public components of the key. ! 1253: * The components are converted to their external (big-endian) ! 1254: * representation, concatenated, and an MD5 on the bit values ! 1255: * (i.e. excluding the length value) calculated and displayed in hex. ! 1256: * ! 1257: * The hash, or "fingerprint", of the key is useful mainly for quickly ! 1258: * and easily verifying over the phone that you have a good copy of ! 1259: * someone's public key. Just read the hash over the phone and have ! 1260: * them check it against theirs. ! 1261: */ ! 1262: void getKeyHash(byte * hash, unitptr n, unitptr e) ! 1263: { ! 1264: struct MD5Context mdContext; ! 1265: byte buffer[MAX_BYTE_PRECISION + 2]; ! 1266: byte mdBuffer[MAX_BYTE_PRECISION * 2]; ! 1267: int i, mdIndex = 0, bufIndex; ! 1268: ! 1269: /* Convert n and e to external (big-endian) byte order and move to mdBuffer */ ! 1270: i = reg2mpi(buffer, n); ! 1271: for (bufIndex = 2; bufIndex < i + 2; bufIndex++) /* +2 skips count */ ! 1272: mdBuffer[mdIndex++] = buffer[bufIndex]; ! 1273: i = reg2mpi(buffer, e); ! 1274: for (bufIndex = 2; bufIndex < i + 2; bufIndex++) /* +2 skips count */ ! 1275: mdBuffer[mdIndex++] = buffer[bufIndex]; ! 1276: ! 1277: /* Now evaluate the MD5 for the two MPI's */ ! 1278: MD5Init(&mdContext); ! 1279: MD5Update(&mdContext, mdBuffer, mdIndex); ! 1280: MD5Final(hash, &mdContext); ! 1281: ! 1282: } /* getKeyHash */ ! 1283: ! 1284: ! 1285: void printKeyHash(byteptr hash, boolean indent) ! 1286: { ! 1287: int i; ! 1288: #ifdef MACTC5 ! 1289: char str[256],*start=str; ! 1290: #endif ! 1291: ! 1292: /* Display the hash. The format is: ! 1293: pub 1024/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ! 1294: Key fingerprint = xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx ! 1295: */ ! 1296: fprintf(pgpout, "%*s", indent ? 29 : 1, LANG("Key fingerprint =")); ! 1297: for (i = 0; i < 8; i++) ! 1298: fprintf(pgpout, " %02X", hash[i]); ! 1299: putc(' ', pgpout); ! 1300: for (i = 8; i < 16; i++) ! 1301: fprintf(pgpout, " %02X", hash[i]); ! 1302: putc('\n', pgpout); ! 1303: ! 1304: #ifdef MACTC5 ! 1305: start+=sprintf(start, "%s", LANG("Key fingerprint =" ) ); /* CP */ ! 1306: for( i = 0; i < 8; i++ ) ! 1307: start+=sprintf(start, "%02X ", hash[ i ] ); ! 1308: *(start++)=' '; ! 1309: for( i = 8; i < 16; i++ ) ! 1310: start+=sprintf(start, "%02X ", hash[ i ] ); ! 1311: *(--start)=0; /* Remove trailing space */ ! 1312: AddResult(str); ! 1313: #endif ! 1314: } /* printKeyHash */ ! 1315: ! 1316: ! 1317: void showKeyHash(unitptr n, unitptr e) ! 1318: { ! 1319: byte hash[16]; ! 1320: ! 1321: getKeyHash(hash, n, e); /* compute hash of (n,e) */ ! 1322: ! 1323: printKeyHash(hash, TRUE); ! 1324: } /* showKeyHash */ ! 1325: ! 1326: /* ! 1327: * Lists all entries in keyring that have mcguffin string in userid. ! 1328: * mcguffin is a null-terminated C string. ! 1329: */ ! 1330: int view_keyring(char *mcguffin, char *ringfile, boolean show_signatures, ! 1331: boolean show_hashes) ! 1332: { ! 1333: FILE *f; ! 1334: int status; ! 1335: char dfltring[MAX_PATH]; ! 1336: int keycounter = 0; ! 1337: FILE *savepgpout; ! 1338: ! 1339: /* Default keyring to check signature ID's */ ! 1340: strcpy(dfltring, globalPubringName); ! 1341: ! 1342: /* open file f for read, in binary (not text) mode... */ ! 1343: if ((f = fopen(ringfile, FOPRBIN)) == NULL) { ! 1344: fprintf(pgpout, ! 1345: LANG("\n\007Can't open key ring file '%s'\n"), ringfile); ! 1346: return -1; ! 1347: } ! 1348: if (show_signatures) { ! 1349: setkrent(ringfile); ! 1350: setkrent(dfltring); ! 1351: init_userhash(); ! 1352: } ! 1353: /* Here's a good format for display of key or signature certificates: ! 1354: Type bits/keyID Date User ID ! 1355: pub 1024/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ! 1356: sec 512/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ! 1357: sig 384/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ! 1358: */ ! 1359: ! 1360: /* XXX Send this to stdout. Do we always want to do this? ! 1361: * Why couldn't we have a PGPOUT and PGPERR, and then we wouldn't ! 1362: * have this problem? -warlord ! 1363: */ ! 1364: savepgpout = pgpout; ! 1365: pgpout = stdout; ! 1366: ! 1367: if (moreflag) ! 1368: open_more(); ! 1369: if (!quietmode) { ! 1370: fprintf(pgpout, LANG("\nKey ring: '%s'"), ringfile); ! 1371: if (mcguffin && strlen(mcguffin) > 0) ! 1372: fprintf(pgpout, ! 1373: LANG(", looking for user ID \"%s\"."), ! 1374: LOCAL_CHARSET(mcguffin)); ! 1375: } ! 1376: ! 1377: fprintf(pgpout, "\n"); ! 1378: kv_title(pgpout); ! 1379: status = kvformat_keypacket(f, pgpout, FALSE, mcguffin, ringfile, ! 1380: show_signatures, show_hashes, &keycounter); ! 1381: ! 1382: fclose(f); /* close key file */ ! 1383: if (show_signatures) ! 1384: endkrent(); ! 1385: if (keycounter == 1) ! 1386: fprintf(pgpout, LANG("1 matching key found.\n")); ! 1387: else ! 1388: fprintf(pgpout, LANG("%d matching keys found.\n"), keycounter); ! 1389: close_more(); ! 1390: pgpout = savepgpout; ! 1391: ! 1392: if (status < 0) ! 1393: return status; ! 1394: if (mcguffin != NULL && *mcguffin != '\0') { ! 1395: /* user specified substring */ ! 1396: if (keycounter == 0) ! 1397: return 67; /* user not found */ ! 1398: else if (keycounter > 1) ! 1399: return 1; /* more than one match */ ! 1400: } ! 1401: return 0; /* normal return */ ! 1402: ! 1403: } /* view_keyring */ ! 1404: ! 1405: /* Lists all entries in keyring that have mcguffin string in userid. ! 1406: mcguffin is a null-terminated C string. ! 1407: If options is CHECK_NEW, only new signatures are checked and are ! 1408: marked as being checked in the trustbyte (called from addto_keyring). ! 1409: */ ! 1410: int dokeycheck(char *mcguffin, char *ringfile, int options) ! 1411: { ! 1412: FILE *f, *fixedf = NULL; ! 1413: byte ctb, keyctb = 0; ! 1414: long fpsig = 0, fpkey = 0, fixpos = 0, trustpos = -1; ! 1415: int status, sigstatus; ! 1416: int keypktlen = 0, sigpktlen = 0; ! 1417: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1418: byte keyID[KEYFRAGSIZE]; ! 1419: byte sigkeyID[KEYFRAGSIZE]; ! 1420: byte keyuserid[256]; /* key certificate userid */ ! 1421: byte siguserid[256]; /* sig certificate userid */ ! 1422: char dfltring[MAX_PATH]; ! 1423: char *tempring = NULL; ! 1424: word32 tstamp; ! 1425: byte *timestamp = (byte *) & tstamp; /* key certificate timestamp */ ! 1426: word32 sigtstamp; ! 1427: byte *sigtimestamp = (byte *) & sigtstamp; ! 1428: byte sigclass; ! 1429: int firstuser = 0; ! 1430: int compromised = 0; ! 1431: boolean invalid_key = FALSE; /* unsupported version or bad data */ ! 1432: boolean failed = FALSE; ! 1433: boolean print_userid = FALSE; ! 1434: byte sigtrust, newtrust; ! 1435: FILE *savepgpout; ! 1436: ! 1437: /* Default keyring to check signature ID's */ ! 1438: strcpy(dfltring, globalPubringName); ! 1439: ! 1440: /* open file f, in binary (not text) mode... */ ! 1441: f = fopen(ringfile, FOPRWBIN); ! 1442: if (f == NULL) { ! 1443: fprintf(pgpout, ! 1444: LANG("\n\007Can't open key ring file '%s'\n"), ringfile); ! 1445: return -1; ! 1446: } ! 1447: /* Here's a good format for display of key or signature certificates: ! 1448: Type bits/keyID Date User ID ! 1449: pub 1024/xxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ! 1450: sec 512/xxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ! 1451: sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ! 1452: */ ! 1453: ! 1454: /* XXX Send this to stdout. Do we always want to do this? ! 1455: * Why couldn't we have a PGPOUT and PGPERR, and then we wouldn't ! 1456: * have this problem? -warlord ! 1457: */ ! 1458: savepgpout = pgpout; ! 1459: pgpout = stdout; ! 1460: ! 1461: if (options & CHECK_NEW) { ! 1462: fprintf(pgpout, LANG("\nChecking signatures...\n")); ! 1463: } else { ! 1464: if (moreflag) ! 1465: open_more(); ! 1466: if (!quietmode) { ! 1467: fprintf(pgpout, LANG("\nKey ring: '%s'"), ringfile); ! 1468: if (mcguffin && strlen(mcguffin) > 0) ! 1469: fprintf(pgpout, LANG(", looking for user ID \"%s\"."), ! 1470: LOCAL_CHARSET(mcguffin)); ! 1471: } ! 1472: fprintf(pgpout, "\n"); ! 1473: kv_title(pgpout); ! 1474: } ! 1475: for (;;) { ! 1476: long fpos = ftell(f); ! 1477: status = readkeypacket(f, FALSE, &ctb, timestamp, (char *) keyuserid, ! 1478: n, e, ! 1479: NULL, NULL, NULL, NULL, sigkeyID, NULL); ! 1480: /* Note that readkeypacket has called set_precision */ ! 1481: if (status == -1) ! 1482: break; /* eof reached */ ! 1483: if (status == -4 || status == -6) { ! 1484: /* only ctb and userid are valid */ ! 1485: memset(sigkeyID, 0, KEYFRAGSIZE); ! 1486: tstamp = 0; ! 1487: } else if (status < 0) { ! 1488: fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"), ! 1489: ringfile); ! 1490: fclose(f); /* close key file */ ! 1491: return -1; ! 1492: } ! 1493: if (is_key_ctb(ctb)) { ! 1494: firstuser = 1; ! 1495: keyctb = ctb; ! 1496: fpkey = fpos; ! 1497: keypktlen = (int) (ftell(f) - fpkey); ! 1498: compromised = is_compromised(f); ! 1499: if (status < 0) { ! 1500: invalid_key = TRUE; ! 1501: memset(keyID, 0, KEYFRAGSIZE); ! 1502: } else { ! 1503: invalid_key = FALSE; ! 1504: extract_keyID(keyID, n); ! 1505: } ! 1506: if (options & CHECK_NEW) ! 1507: print_userid = TRUE; ! 1508: } ! 1509: if (ctb == CTB_USERID) { ! 1510: #ifdef MACTC5 ! 1511: mac_poll_for_break(); ! 1512: #endif ! 1513: PascalToC((char *) keyuserid); ! 1514: } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 1515: fpsig = fpos; ! 1516: sigpktlen = (int) (ftell(f) - fpsig); ! 1517: } else { ! 1518: continue; ! 1519: } ! 1520: ! 1521: trustpos = ftell(f); ! 1522: status = read_trust(f, &sigtrust); ! 1523: if (status == -1) ! 1524: break; /* EOF */ ! 1525: if (status == -7) { ! 1526: trustpos = -1; ! 1527: continue; /* not a keyring or this was a compromise cert. */ ! 1528: } ! 1529: if (status < 0) { ! 1530: fclose(f); ! 1531: return status; ! 1532: } ! 1533: if (options & CHECK_NEW) { ! 1534: if (!is_ctb_type(ctb, CTB_SKE_TYPE)) ! 1535: continue; ! 1536: if (sigtrust & KC_SIG_CHECKED) ! 1537: continue; ! 1538: /* addto_keyring has called setkrent() */ ! 1539: if (user_from_keyID(sigkeyID) == NULL) ! 1540: continue; /* unknown signator */ ! 1541: } ! 1542: /* If we don't list the signatures, continue */ ! 1543: if (!(options & CHECK_NEW) && ! 1544: !userid_match((char *) keyuserid, mcguffin, n)) ! 1545: continue; ! 1546: ! 1547: if (ctb == CTB_USERID || print_userid) { ! 1548: /* CHECK_NEW: only print userid if it has new signature */ ! 1549: print_userid = FALSE; ! 1550: if (firstuser) { ! 1551: if (is_ctb_type(keyctb, CTB_CERT_PUBKEY_TYPE)) ! 1552: fprintf(pgpout, LANG("pub")); ! 1553: else if (is_ctb_type(keyctb, CTB_CERT_SECKEY_TYPE)) ! 1554: fprintf(pgpout, LANG("sec")); ! 1555: else ! 1556: fprintf(pgpout, "???"); ! 1557: if (invalid_key) ! 1558: fprintf(pgpout, "? "); ! 1559: else ! 1560: fprintf(pgpout, " "); ! 1561: fprintf(pgpout, "%4d/%s %s ", ! 1562: countbits(n), keyIDstring(keyID), cdate(&tstamp)); ! 1563: } else { ! 1564: fprintf(pgpout, " %s ", ! 1565: blankkeyID); ! 1566: } ! 1567: if (compromised && firstuser) { ! 1568: fprintf(pgpout, LANG("*** KEY REVOKED ***\n")); ! 1569: fprintf(pgpout, " %s ", ! 1570: blankkeyID); ! 1571: } ! 1572: firstuser = 0; ! 1573: fprintf(pgpout, "%s\n", LOCAL_CHARSET((char *) keyuserid)); ! 1574: } ! 1575: /* Ignore comments and anything else */ ! 1576: if (!is_ctb_type(ctb, CTB_SKE_TYPE)) ! 1577: continue; ! 1578: ! 1579: /* So now we're checking a signature... */ ! 1580: /* Try checking signature on either this ring or dflt ring */ ! 1581: ! 1582: CToPascal((char *) keyuserid); ! 1583: sigstatus = check_key_sig(f, fpkey, keypktlen, ! 1584: (char *) keyuserid, f, fpsig, ! 1585: ringfile, (char *) siguserid, ! 1586: sigtimestamp, &sigclass); ! 1587: if (sigstatus == -2 && strcmp(ringfile, dfltring) != 0) { ! 1588: sigstatus = check_key_sig(f, fpkey, keypktlen, ! 1589: (char *) keyuserid, f, fpsig, ! 1590: dfltring, (char *) siguserid, ! 1591: sigtimestamp, &sigclass); ! 1592: } ! 1593: /* ! 1594: * Note: sigstatus has the following values: ! 1595: * 0 Good signature ! 1596: * -1 Generic error ! 1597: * -2 Can't find key ! 1598: * -3 Key too big ! 1599: * -4 Key too small ! 1600: * -5 Maybe malformed RSA (RSAREF) ! 1601: * -6 Unknown PK algorithm ! 1602: * -7 Unknown conventional algorithm ! 1603: * -8 Unknown version ! 1604: * -9 Malformed RSA packet ! 1605: * -10 Malformed packet ! 1606: * -20 BAD SIGNATURE ! 1607: */ ! 1608: PascalToC((char *) keyuserid); ! 1609: fseek(f, fpsig + sigpktlen, SEEK_SET); ! 1610: if (sigclass == KC_SIGNATURE_BYTE) ! 1611: fprintf(pgpout, LANG("com")); ! 1612: else ! 1613: fprintf(pgpout, LANG("sig")); ! 1614: if (sigstatus >= 0) ! 1615: fputs("! ", pgpout); /* Good */ ! 1616: else if (status < 0 || sigstatus == -2 || sigstatus == -3) ! 1617: fputs("? ", pgpout); /* Uncheckable */ ! 1618: else if (sigstatus != -20) ! 1619: fputs("% ", pgpout); /* Malformed */ ! 1620: else ! 1621: fputs("* ", pgpout); /* BAD! */ ! 1622: ! 1623: showkeyID(sigkeyID, pgpout); ! 1624: ! 1625: /* If we got a keyID, show it */ ! 1626: if (sigstatus >= 0 || sigstatus == -3 || ! 1627: (sigstatus <= -5 && sigstatus >= -9) || ! 1628: sigstatus == -20) { ! 1629: PascalToC((char *) siguserid); ! 1630: fprintf(pgpout, " %s ", cdate(&sigtstamp)); ! 1631: if (sigclass != KC_SIGNATURE_BYTE) ! 1632: putc(' ', pgpout); ! 1633: fputs(LOCAL_CHARSET((char *) siguserid), pgpout); ! 1634: putc('\n', pgpout); ! 1635: /* If an error, prepare next line for message */ ! 1636: if (sigstatus < 0) ! 1637: fprintf(pgpout, " %s ", ! 1638: blankkeyID); ! 1639: } else { ! 1640: /* Indent error messages past date field */ ! 1641: fprintf(pgpout, " "); ! 1642: } ! 1643: ! 1644: /* Compute new trust */ ! 1645: newtrust = sigtrust; ! 1646: if (sigstatus >= 0) { ! 1647: newtrust |= KC_SIG_CHECKED; ! 1648: } else if (sigstatus == -2) { ! 1649: newtrust |= KC_SIG_CHECKED; ! 1650: newtrust &= ~KC_SIGTRUST_MASK; ! 1651: } else { ! 1652: newtrust &= ~KC_SIGTRUST_MASK & ~KC_SIG_CHECKED; ! 1653: newtrust |= KC_SIGTRUST_UNTRUSTED; ! 1654: } ! 1655: ! 1656: /* If it changed, write it out */ ! 1657: if (trustpos > 0 && newtrust != sigtrust) ! 1658: write_trust_pos(f, newtrust, trustpos); ! 1659: if (sigstatus >= 0) ! 1660: continue; /* Skip error code */ ! 1661: ! 1662: /* An error: print an appropriate message */ ! 1663: if (sigstatus == -2) ! 1664: fprintf(pgpout, LANG("(Unknown signator, can't be checked)")); ! 1665: else if (sigstatus == -3) ! 1666: fprintf(pgpout, LANG("(Key too long, can't be checked)")); ! 1667: else if (sigstatus == -5) ! 1668: fprintf(pgpout, LANG("(Malformed or obsolete signature format)")); ! 1669: else if (sigstatus == -6) ! 1670: fprintf(pgpout, LANG("(Unknown public-key algorithm)")); ! 1671: else if (sigstatus == -7) ! 1672: fprintf(pgpout, LANG("(Unknown hash algorithm)")); ! 1673: else if (sigstatus == -8) ! 1674: fprintf(pgpout, LANG("(Unknown signature packet version)")); ! 1675: else if (sigstatus == -9) ! 1676: fprintf(pgpout, LANG("(Malformed signature)")); ! 1677: else if (sigstatus == -10) ! 1678: fprintf(pgpout, LANG("(Corrupted signature packet)")); ! 1679: else if (sigstatus == -20) ! 1680: fprintf(pgpout, LANG("\007**** BAD SIGNATURE! ****")); ! 1681: else ! 1682: fprintf(pgpout, "(Unexpected signature error %d)", sigstatus); ! 1683: putc('\n', pgpout); ! 1684: ! 1685: /* ! 1686: * If the signature was not too bad, leave it on the key ! 1687: * ring. ! 1688: */ ! 1689: if (sigstatus == -2 || sigstatus == -3) ! 1690: continue; ! 1691: /* ! 1692: * The signature was unacceptable, and ! 1693: * likely to remain that way, so remove it ! 1694: * from the keyring. ! 1695: */ ! 1696: if (!failed) { ! 1697: /* first bad signature: create scratch file */ ! 1698: tempring = tempfile(TMP_TMPDIR); ! 1699: fixedf = fopen(tempring, FOPWBIN); ! 1700: failed = TRUE; ! 1701: } ! 1702: if (fixedf != NULL) { ! 1703: copyfilepos(f, fixedf, fpsig - fixpos, fixpos); ! 1704: fseek(f, fpsig + sigpktlen, SEEK_SET); ! 1705: if (nextkeypacket(f, &ctb) < 0 || ctb != CTB_KEYCTRL) ! 1706: fseek(f, fpsig + sigpktlen, SEEK_SET); ! 1707: fixpos = ftell(f); ! 1708: } ! 1709: } /* loop for all packets */ ! 1710: ! 1711: close_more(); ! 1712: pgpout = savepgpout; ! 1713: ! 1714: if (status < -1) { ! 1715: fclose(f); ! 1716: return status; ! 1717: } ! 1718: fputc('\n', pgpout); ! 1719: ! 1720: if (failed && fixedf) { ! 1721: copyfilepos(f, fixedf, -1L, fixpos); ! 1722: fclose(f); ! 1723: if (write_error(fixedf)) { ! 1724: fclose(fixedf); ! 1725: return -1; ! 1726: } ! 1727: fclose(fixedf); ! 1728: if (!batchmode) ! 1729: fprintf(pgpout, LANG("Remove bad signatures (Y/n)? ")); ! 1730: if (batchmode || getyesno('y')) { ! 1731: savetempbak(tempring, ringfile); ! 1732: failed = 0; ! 1733: } ! 1734: } else { ! 1735: fclose(f); ! 1736: } ! 1737: ! 1738: return 0; /* normal return */ ! 1739: ! 1740: } /* dokeycheck */ ! 1741: ! 1742: int backup_rename(char *scratchfile, char *destfile) ! 1743: { ! 1744: /* rename scratchfile to destfile after making a backup file */ ! 1745: char bakfile[MAX_PATH]; ! 1746: ! 1747: if (is_tempfile(destfile)) { ! 1748: remove(destfile); ! 1749: } else { ! 1750: if (file_exists(destfile)) { ! 1751: strcpy(bakfile, destfile); ! 1752: force_extension(bakfile, BAK_EXTENSION); ! 1753: remove(bakfile); ! 1754: rename(destfile, bakfile); ! 1755: } ! 1756: } ! 1757: return rename2(scratchfile, destfile); ! 1758: } ! 1759: ! 1760: /* Lists all signatures for keys with specified mcguffin string, and asks ! 1761: * if they should be removed. ! 1762: */ ! 1763: int remove_sigs(char *mcguffin, char *ringfile) ! 1764: { ! 1765: FILE *f, *g; ! 1766: byte ctb; ! 1767: long fp, fpuser; ! 1768: int packetlength; ! 1769: int status; ! 1770: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1771: byte sigkeyID[KEYFRAGSIZE]; ! 1772: byte userid[256]; /* key certificate userid */ ! 1773: char dfltring[MAX_PATH]; ! 1774: word32 tstamp; ! 1775: byte *timestamp = (byte *) & tstamp; /* key certificate timestamp */ ! 1776: int nsigs = 0, nremoved = 0; ! 1777: int keeping; ! 1778: char *scratchf; ! 1779: ! 1780: /* Default keyring to check signature ID's */ ! 1781: strcpy(dfltring, globalPubringName); ! 1782: ! 1783: if (!mcguffin || strlen(mcguffin) == 0) ! 1784: return -1; ! 1785: ! 1786: setoutdir(ringfile); ! 1787: scratchf = tempfile(0); ! 1788: ! 1789: strcpy((char *) userid, mcguffin); ! 1790: ! 1791: fprintf(pgpout, ! 1792: LANG("\nRemoving signatures from userid '%s' in key ring '%s'\n"), ! 1793: LOCAL_CHARSET(mcguffin), ringfile); ! 1794: ! 1795: status = getpublickey(GPK_GIVEUP | GPK_SHOW, ringfile, &fp, ! 1796: &packetlength, NULL, timestamp, userid, n, e); ! 1797: if (status < 0) { ! 1798: fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"), ! 1799: ringfile); ! 1800: return 0; /* normal return */ ! 1801: } ! 1802: strcpy((char *) userid, mcguffin); ! 1803: getpubuserid(ringfile, fp, userid, &fpuser, &packetlength, FALSE); ! 1804: packetlength += (int) (fpuser - fp); ! 1805: ! 1806: /* open file f for read, in binary (not text) mode... */ ! 1807: if ((f = fopen(ringfile, FOPRBIN)) == NULL) { ! 1808: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"), ! 1809: ringfile); ! 1810: return -1; ! 1811: } ! 1812: /* Count signatures */ ! 1813: fseek(f, fp + packetlength, SEEK_SET); ! 1814: for (;;) { ! 1815: status = nextkeypacket(f, &ctb); ! 1816: if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID) ! 1817: break; ! 1818: if (is_ctb_type(ctb, CTB_SKE_TYPE)) ! 1819: ++nsigs; ! 1820: } ! 1821: ! 1822: rewind(f); ! 1823: ! 1824: if (nsigs == 0) { ! 1825: fprintf(pgpout, LANG("\nKey has no signatures to remove.\n")); ! 1826: fclose(f); ! 1827: return 0; /* Normal return */ ! 1828: } ! 1829: fprintf(pgpout, LANG("\nKey has %d signature(s):\n"), nsigs); ! 1830: ! 1831: /* open file g for writing, in binary (not text) mode... */ ! 1832: if ((g = fopen(scratchf, FOPWBIN)) == NULL) { ! 1833: fclose(f); ! 1834: return -1; ! 1835: } ! 1836: copyfile(f, g, fp + packetlength); /* copy file f to g up through key */ ! 1837: ! 1838: /* Now print out any following sig certs */ ! 1839: keeping = 1; ! 1840: for (;;) { ! 1841: fp = ftell(f); ! 1842: status = readkeypacket(f, FALSE, &ctb, NULL, NULL, NULL, NULL, ! 1843: NULL, NULL, NULL, NULL, sigkeyID, NULL); ! 1844: packetlength = (int) (ftell(f) - fp); ! 1845: if ((status < 0 && status != -6 && status != -4) || ! 1846: is_key_ctb(ctb) || ctb == CTB_USERID) ! 1847: break; ! 1848: if (is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 1849: fprintf(pgpout, LANG("sig")); ! 1850: fprintf(pgpout, "%c ", status < 0 ? '?' : ' '); ! 1851: if (status < 0) ! 1852: memset(sigkeyID, 0, KEYFRAGSIZE); ! 1853: showkeyID(sigkeyID, pgpout); ! 1854: fprintf(pgpout, " "); /* Indent signator userid */ ! 1855: if (getpublickey(GPK_GIVEUP, ringfile, NULL, NULL, ! 1856: sigkeyID, timestamp, userid, n, e) >= 0 || ! 1857: getpublickey(GPK_GIVEUP, dfltring, NULL, NULL, ! 1858: sigkeyID, timestamp, userid, n, e) >= 0) { ! 1859: PascalToC((char *) userid); ! 1860: fprintf(pgpout, "%s\n", LOCAL_CHARSET((char *) userid)); ! 1861: } else { ! 1862: fprintf(pgpout, ! 1863: LANG("(Unknown signator, can't be checked)\n")); ! 1864: } ! 1865: fprintf(pgpout, LANG("Remove this signature (y/N)? ")); ! 1866: if (!(keeping = !getyesno('n'))) ! 1867: ++nremoved; ! 1868: } ! 1869: if (keeping) ! 1870: copyfilepos(f, g, (long) packetlength, fp); ! 1871: } /* scanning sig certs */ ! 1872: copyfilepos(f, g, -1L, fp); /* Copy rest of file */ ! 1873: ! 1874: fclose(f); /* close key file */ ! 1875: if (write_error(g)) { ! 1876: fclose(g); ! 1877: return -1; ! 1878: } ! 1879: fclose(g); /* close scratch file */ ! 1880: savetempbak(scratchf, ringfile); ! 1881: if (nremoved == 0) ! 1882: fprintf(pgpout, LANG("\nNo key signatures removed.\n")); ! 1883: else ! 1884: fprintf(pgpout, LANG("\n%d key signature(s) removed.\n"), nremoved); ! 1885: ! 1886: return 0; /* normal return */ ! 1887: ! 1888: } /* remove_sigs */ ! 1889: ! 1890: /* ! 1891: * Remove the first entry in key ring that has mcguffin string in userid. ! 1892: * Or it removes the first matching keyID from the ring. ! 1893: * A non-NULL keyID takes precedence over a mcguffin specifier. ! 1894: * mcguffin is a null-terminated C string. ! 1895: * If secring_too is TRUE, the secret keyring is also checked. ! 1896: */ ! 1897: int remove_from_keyring(byte * keyID, char *mcguffin, ! 1898: char *ringfile, boolean secring_too) ! 1899: { ! 1900: FILE *f; ! 1901: FILE *g; ! 1902: long fp, nfp; ! 1903: int packetlength; ! 1904: byte ctb; ! 1905: int status; ! 1906: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 1907: byte userid[256]; /* key certificate userid */ ! 1908: word32 tstamp; ! 1909: byte *timestamp = (byte *) & tstamp; /* key certificate timestamp */ ! 1910: int userids; ! 1911: boolean rmuserid = FALSE; ! 1912: char *scratchf; ! 1913: unsigned secflag = 0; ! 1914: ! 1915: default_extension(ringfile, PGP_EXTENSION); ! 1916: ! 1917: if ((keyID == NULL) && (!mcguffin || strlen(mcguffin) == 0)) ! 1918: return -1; /* error, null mcguffin will match everything */ ! 1919: ! 1920: top: ! 1921: if (mcguffin) ! 1922: strcpy((char *) userid, mcguffin); ! 1923: ! 1924: fprintf(pgpout, LANG("\nRemoving from key ring: '%s'"), ringfile); ! 1925: if (mcguffin && strlen(mcguffin) > 0) ! 1926: fprintf(pgpout, LANG(", userid \"%s\".\n"), ! 1927: LOCAL_CHARSET(mcguffin)); ! 1928: ! 1929: status = getpublickey(secflag | GPK_GIVEUP | GPK_SHOW, ringfile, &fp, ! 1930: &packetlength, NULL, timestamp, userid, n, e); ! 1931: if (status < 0 && status != -4 && status != -6) { ! 1932: fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"), ! 1933: ringfile); ! 1934: return 0; /* normal return */ ! 1935: } ! 1936: /* Now add to packetlength the subordinate following certificates */ ! 1937: if ((f = fopen(ringfile, FOPRBIN)) == NULL) { ! 1938: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"), ! 1939: ringfile); ! 1940: return -1; ! 1941: } ! 1942: fseek(f, fp + packetlength, SEEK_SET); ! 1943: userids = 0; ! 1944: do { /* count user ID's, position nfp at next key */ ! 1945: nfp = ftell(f); ! 1946: status = nextkeypacket(f, &ctb); ! 1947: if (status == 0 && ctb == CTB_USERID) ! 1948: ++userids; ! 1949: } while (status == 0 && !is_key_ctb(ctb)); ! 1950: if (status < -1) { ! 1951: fclose(f); ! 1952: return -1; ! 1953: } ! 1954: if (keyID == NULL) { /* Human confirmation is required. */ ! 1955: /* Supposedly the key was fully displayed by getpublickey */ ! 1956: if (userids > 1) { ! 1957: fprintf(pgpout, LANG("\nKey has more than one user ID.\n\ ! 1958: Do you want to remove the whole key (y/N)? ")); ! 1959: if (!getyesno('n')) { ! 1960: /* find out which userid should be removed */ ! 1961: rmuserid = TRUE; ! 1962: fseek(f, fp + packetlength, SEEK_SET); ! 1963: for (;;) { ! 1964: fp = ftell(f); ! 1965: status = readkpacket(f, &ctb, (char *) userid, NULL, NULL); ! 1966: if (status < 0 && status != -4 && status != -6 ! 1967: || is_key_ctb(ctb)) { ! 1968: fclose(f); ! 1969: fprintf(pgpout, LANG("\nNo more user ID's\n")); ! 1970: return -1; ! 1971: } ! 1972: if (ctb == CTB_USERID) { ! 1973: fprintf(pgpout, LANG("Remove \"%s\" (y/N)? "), userid); ! 1974: if (getyesno('n')) ! 1975: break; ! 1976: } ! 1977: } ! 1978: do { /* also remove signatures and trust bytes */ ! 1979: nfp = ftell(f); ! 1980: status = nextkeypacket(f, &ctb); ! 1981: } while ((status == 0 || status == -4 || status == -6) && ! 1982: !is_key_ctb(ctb) && ctb != CTB_USERID); ! 1983: if (status < -1 && status != -4 && status != -6) { ! 1984: fclose(f); ! 1985: return -1; ! 1986: } ! 1987: } ! 1988: } else if (!force_flag) { /* only one user ID */ ! 1989: fprintf(pgpout, ! 1990: LANG("\nAre you sure you want this key removed (y/N)? ")); ! 1991: if (!getyesno('n')) { ! 1992: fclose(f); ! 1993: return -1; /* user said "no" */ ! 1994: } ! 1995: } ! 1996: } ! 1997: fclose(f); ! 1998: packetlength = (int) (nfp - fp); ! 1999: ! 2000: /* open file f for read, in binary (not text) mode... */ ! 2001: if ((f = fopen(ringfile, FOPRBIN)) == NULL) { ! 2002: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"), ! 2003: ringfile); ! 2004: return -1; ! 2005: } ! 2006: setoutdir(ringfile); ! 2007: scratchf = tempfile(0); ! 2008: /* open file g for writing, in binary (not text) mode... */ ! 2009: if ((g = fopen(scratchf, FOPWBIN)) == NULL) { ! 2010: fclose(f); ! 2011: return -1; ! 2012: } ! 2013: copyfilepos(f, g, fp, 0L); /* copy file f to g up to position fp */ ! 2014: copyfilepos(f, g, -1L, fp + packetlength); /* copy rest of file f */ ! 2015: fclose(f); /* close key file */ ! 2016: if (write_error(g)) { ! 2017: fclose(g); ! 2018: return -1; ! 2019: } ! 2020: fclose(g); /* close scratch file */ ! 2021: if (secring_too) /* TRUE if this is the public keyring */ ! 2022: maint_update(scratchf, 0); ! 2023: savetempbak(scratchf, ringfile); ! 2024: if (rmuserid) ! 2025: fprintf(pgpout, LANG("\nUser ID removed from key ring.\n")); ! 2026: else ! 2027: fprintf(pgpout, LANG("\nKey removed from key ring.\n")); ! 2028: ! 2029: if (secring_too) { ! 2030: secring_too = FALSE; ! 2031: strcpy(ringfile, globalSecringName); ! 2032: strcpy((char *) userid, mcguffin); ! 2033: if (getpublickey(GPK_GIVEUP | GPK_SECRET, ringfile, NULL, ! 2034: NULL, NULL, timestamp, userid, n, e) == 0) { ! 2035: fprintf(pgpout, ! 2036: LANG("\nKey or user ID is also present in secret keyring.\n\ ! 2037: Do you also want to remove it from the secret keyring (y/N)? ")); ! 2038: if (getyesno('n')) { ! 2039: secflag = GPK_SECRET; ! 2040: goto top; ! 2041: } ! 2042: } ! 2043: } ! 2044: return 0; /* normal return */ ! 2045: ! 2046: } /* remove_from_keyring */ ! 2047: ! 2048: /* ! 2049: * Copy the first entry in key ring that has mcguffin string in ! 2050: * userid and put it into keyfile. ! 2051: * mcguffin is a null-terminated C string. ! 2052: */ ! 2053: int extract_from_keyring(char *mcguffin, char *keyfile, char *ringfile, ! 2054: boolean transflag) ! 2055: { ! 2056: FILE *f; ! 2057: FILE *g; ! 2058: long fp; ! 2059: int packetlength = 0; ! 2060: byte ctb; ! 2061: byte keyctrl; ! 2062: int status; ! 2063: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 2064: byte keyID[KEYFRAGSIZE]; ! 2065: byte userid[256]; /* key certificate userid */ ! 2066: char fname[MAX_PATH], transfile[MAX_PATH], transname[MAX_PATH]; ! 2067: char *tempf = NULL; ! 2068: word32 tstamp; ! 2069: byte *timestamp = (byte *) & tstamp; /* key cert tstamp */ ! 2070: boolean append = FALSE; ! 2071: boolean whole_ring = FALSE; ! 2072: ! 2073: default_extension(ringfile, PGP_EXTENSION); ! 2074: ! 2075: if (!mcguffin || strlen(mcguffin) == 0 || strcmp(mcguffin, "*") == 0) ! 2076: whole_ring = TRUE; ! 2077: ! 2078: /* open file f for read, in binary (not text) mode... */ ! 2079: if ((f = fopen(ringfile, FOPRBIN)) == NULL) { ! 2080: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"), ! 2081: ringfile); ! 2082: return -1; ! 2083: } ! 2084: if (!whole_ring) { ! 2085: strcpy((char *) userid, mcguffin); ! 2086: fprintf(pgpout, LANG("\nExtracting from key ring: '%s'"), ringfile); ! 2087: fprintf(pgpout, LANG(", userid \"%s\".\n"), LOCAL_CHARSET(mcguffin)); ! 2088: ! 2089: status = getpublickey(GPK_GIVEUP | GPK_SHOW, ! 2090: ringfile, &fp, &packetlength, NULL, ! 2091: timestamp, userid, n, e); ! 2092: if (status < 0 && status != -4 && status != -6) { ! 2093: fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"), ! 2094: ringfile); ! 2095: fclose(f); ! 2096: return 1; /* non-normal return */ ! 2097: } ! 2098: extract_keyID(keyID, n); ! 2099: } else { ! 2100: do /* set fp to first key packet */ ! 2101: fp = ftell(f); ! 2102: while ((status = nextkeypacket(f, &ctb)) >= 0 && !is_key_ctb(ctb)); ! 2103: if (status < 0) { ! 2104: fclose(f); ! 2105: return -1; ! 2106: } ! 2107: packetlength = (int) (ftell(f) - fp); ! 2108: } ! 2109: ! 2110: if (!keyfile || strlen(keyfile) == 0) { ! 2111: fprintf(pgpout, "\n"); ! 2112: fprintf(pgpout, LANG("Extract the above key into which file?")); ! 2113: fprintf(pgpout, " "); ! 2114: if (batchmode) ! 2115: return -1; ! 2116: #ifdef MACTC5 ! 2117: if(!GetFilePath(LANG("Extract the above key into which file?"), fname, PUTFILE)) { ! 2118: Putchar('\n'); ! 2119: fname[0]='\0'; ! 2120: return -1; ! 2121: } ! 2122: fprintf(pgpout,fname); ! 2123: #else ! 2124: getstring(fname, sizeof(fname) - 4, TRUE); ! 2125: #endif ! 2126: if (*fname == '\0') ! 2127: return -1; ! 2128: } else { ! 2129: strcpy(fname, keyfile); ! 2130: } ! 2131: default_extension(fname, PGP_EXTENSION); ! 2132: ! 2133: /* If transport armoring, use a dummy file for keyfile */ ! 2134: if (transflag) { ! 2135: strcpy(transname, fname); ! 2136: strcpy(transfile, fname); ! 2137: force_extension(transfile, ASC_EXTENSION); ! 2138: tempf = tempfile(TMP_TMPDIR | TMP_WIPE); ! 2139: strcpy(fname, tempf); ! 2140: } ! 2141: if (file_exists(transflag ? transfile : fname)) { ! 2142: if (!transflag && !whole_ring) { ! 2143: /* see if the key is already present in fname */ ! 2144: status = getpublickey(GPK_GIVEUP, fname, NULL, NULL, keyID, ! 2145: timestamp, userid, n, e); ! 2146: if (status >= 0 || status == -4 || status == -6) { ! 2147: fclose(f); ! 2148: fprintf(pgpout, ! 2149: LANG("Key ID %s is already included in key ring '%s'.\n"), ! 2150: keyIDstring(keyID), fname); ! 2151: return -1; ! 2152: } ! 2153: } ! 2154: if (whole_ring || transflag || status < -1) { ! 2155: if (!is_tempfile(fname) && !force_flag) ! 2156: /* Don't ask this for mailmode or for ! 2157: * a tempfile, since its ok. ! 2158: */ ! 2159: { ! 2160: /* if status < -1 then fname is not a keyfile, ! 2161: ask if it should be overwritten */ ! 2162: fprintf(pgpout, ! 2163: LANG("\n\007Output file '%s' already exists. Overwrite (y/N)? "), ! 2164: transflag ? transfile : fname); ! 2165: if (!getyesno('n')) { ! 2166: fclose(f); ! 2167: return -1; /* user chose to abort */ ! 2168: } ! 2169: } ! 2170: } else { ! 2171: append = TRUE; ! 2172: } ! 2173: } ! 2174: if (append) ! 2175: g = fopen(fname, FOPRWBIN); ! 2176: else ! 2177: g = fopen(fname, FOPWBIN); ! 2178: if (g == NULL) { ! 2179: if (append) ! 2180: fprintf(pgpout, ! 2181: LANG("\n\007Can't open key ring file '%s'\n"), ringfile); ! 2182: else ! 2183: fprintf(pgpout, ! 2184: LANG("\n\007Unable to create key file '%s'.\n"), fname); ! 2185: fclose(f); ! 2186: return -1; ! 2187: } ! 2188: if (append) ! 2189: fseek(g, 0L, SEEK_END); ! 2190: do { ! 2191: /* file f is positioned right after key packet */ ! 2192: if (whole_ring && read_trust(f, &keyctrl) == 0 ! 2193: && (keyctrl & KC_DISABLED)) { ! 2194: do { /* skip this key */ ! 2195: fp = ftell(f); ! 2196: status = nextkeypacket(f, &ctb); ! 2197: packetlength = (int) (ftell(f) - fp); ! 2198: } ! 2199: while (!is_key_ctb(ctb) && status >= 0); ! 2200: continue; ! 2201: } ! 2202: if (copyfilepos(f, g, (long) packetlength, fp) < 0) { ! 2203: /* Copy key out */ ! 2204: status = -2; ! 2205: break; ! 2206: } ! 2207: /* Copy any following signature or userid packets */ ! 2208: for (;;) { ! 2209: fp = ftell(f); ! 2210: status = nextkeypacket(f, &ctb); ! 2211: packetlength = (int) (ftell(f) - fp); ! 2212: if (status < 0 || is_key_ctb(ctb)) ! 2213: break; ! 2214: if (ctb == CTB_USERID || is_ctb_type(ctb, CTB_SKE_TYPE)) ! 2215: if (copyfilepos(f, g, (long) packetlength, fp) < 0) { ! 2216: status = -2; ! 2217: break; ! 2218: } ! 2219: } ! 2220: } ! 2221: while (whole_ring && status >= 0); ! 2222: ! 2223: fclose(f); ! 2224: if (status < -1 || write_error(g)) { ! 2225: fclose(g); ! 2226: return -1; ! 2227: } ! 2228: fclose(g); ! 2229: ! 2230: if (transflag) { ! 2231: do { ! 2232: char *t; ! 2233: force_extension(transfile, ASC_EXTENSION); ! 2234: if (!file_exists(transfile)) break; ! 2235: t=ck_dup_output(transfile, TRUE, TRUE); ! 2236: if (t==NULL) user_error(); ! 2237: strcpy(transfile,t); ! 2238: } while (TRUE); ! 2239: status = armor_file(fname, transfile, transname, NULL, !whole_ring); ! 2240: rmtemp(tempf); ! 2241: if (status) ! 2242: return -1; ! 2243: } ! 2244: fprintf(pgpout, LANG("\nKey extracted to file '%s'.\n"), ! 2245: transflag ? transfile : fname); ! 2246: ! 2247: return 0; /* normal return */ ! 2248: } /* extract_from_keyring */ ! 2249: ! 2250: ! 2251: /*======================================================================*/ ! 2252: ! 2253: /* Copy the key data in keyfile into ringfile, replacing the data that ! 2254: is in ringfile starting at fp and for length packetlength. ! 2255: keylen is the number of bytes to copy from keyfile ! 2256: */ ! 2257: static int merge_key_to_ringfile(char *keyfile, char *ringfile, long fp, ! 2258: int packetlength, long keylen) ! 2259: { ! 2260: FILE *f, *g, *h; ! 2261: char *tempf; ! 2262: int rc; ! 2263: ! 2264: setoutdir(ringfile); ! 2265: tempf = tempfile(TMP_WIPE); ! 2266: /* open file f for reading, binary, as keyring file */ ! 2267: if ((f = fopen(ringfile, FOPRBIN)) == NULL) ! 2268: return -1; ! 2269: /* open file g for writing, binary, as scratch keyring file */ ! 2270: if ((g = fopen(tempf, FOPWBIN)) == NULL) { ! 2271: fclose(f); ! 2272: return -1; ! 2273: } ! 2274: /* open file h for reading, binary, as key file to be inserted */ ! 2275: if ((h = fopen(keyfile, FOPRBIN)) == NULL) { ! 2276: fclose(f); ! 2277: fclose(g); ! 2278: return -1; ! 2279: } ! 2280: /* Copy pre-key keyring data from f to g */ ! 2281: copyfile(f, g, fp); ! 2282: /* Copy temp key data from h to g */ ! 2283: copyfile(h, g, keylen); ! 2284: /* Copy post-key keyring data from f to g */ ! 2285: copyfilepos(f, g, -1L, fp + packetlength); ! 2286: fclose(f); ! 2287: rc = write_error(g); ! 2288: fclose(g); ! 2289: fclose(h); ! 2290: ! 2291: if (!rc) ! 2292: savetempbak(tempf, ringfile); ! 2293: ! 2294: return rc ? -1 : 0; ! 2295: } /* merge_key_to_ringfile */ ! 2296: ! 2297: static int insert_userid(char *keyfile, byte * userid, long fpos) ! 2298: { ! 2299: /* insert userid and trust byte at position fpos in file keyfile */ ! 2300: char *tmpf; ! 2301: FILE *f, *g; ! 2302: ! 2303: tmpf = tempfile(TMP_TMPDIR); ! 2304: if ((f = fopen(keyfile, FOPRBIN)) == NULL) ! 2305: return -1; ! 2306: if ((g = fopen(tmpf, FOPWBIN)) == NULL) { ! 2307: fclose(f); ! 2308: return -1; ! 2309: } ! 2310: copyfile(f, g, fpos); ! 2311: putc(CTB_USERID, g); ! 2312: fwrite(userid, 1, userid[0] + 1, g); ! 2313: write_trust(g, KC_LEGIT_COMPLETE); ! 2314: copyfile(f, g, -1L); ! 2315: fclose(f); ! 2316: if (write_error(g)) { ! 2317: fclose(g); ! 2318: return -1; ! 2319: } ! 2320: fclose(g); ! 2321: return savetempbak(tmpf, keyfile); ! 2322: } ! 2323: ! 2324: int dokeyedit(char *mcguffin, char *ringfile) ! 2325: /* ! 2326: * Edit the userid and/or pass phrase for an RSA key pair, and ! 2327: * put them back into the ring files. ! 2328: */ ! 2329: { ! 2330: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION], ! 2331: p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION]; ! 2332: char *fname, secring[MAX_PATH]; ! 2333: FILE *f; ! 2334: byte userid[256]; ! 2335: byte userid1[256]; ! 2336: word32 timestamp; /* key certificate timestamp */ ! 2337: byte keyID[KEYFRAGSIZE]; ! 2338: boolean hidekey; /* TRUE iff secret key is encrypted */ ! 2339: boolean changed = FALSE, changeID = FALSE; ! 2340: byte ctb; ! 2341: int status; ! 2342: long fpp, fps, fpu, trust_pos, keylen; ! 2343: int pplength = 0, pslength = 0; ! 2344: byte ideakey[16]; ! 2345: byte keyctrl; ! 2346: struct IdeaCfbContext cfb; ! 2347: ! 2348: if (!ringfile || strlen(ringfile) == 0 || !mcguffin ! 2349: || strlen(mcguffin) == 0) ! 2350: return -1; /* Need ringfile name, user name */ ! 2351: ! 2352: if (!file_exists(ringfile)) ! 2353: force_extension(ringfile, PGP_EXTENSION); ! 2354: ! 2355: /* ! 2356: * Although the name of a secret keyring may change in the future, it ! 2357: * is a safe bet that anything named "secring.pgp" will be a secret ! 2358: * key ring for the indefinite future. ! 2359: */ ! 2360: if (!strcmp(file_tail(ringfile), "secring.pgp") || ! 2361: !strcmp(file_tail(ringfile), file_tail(globalSecringName))) { ! 2362: fprintf(pgpout, ! 2363: LANG("\nThis operation may not be performed on a secret keyring.\n\ ! 2364: Defaulting to public keyring.")); ! 2365: strcpy(ringfile, globalPubringName); ! 2366: } ! 2367: strcpy((char *) userid, mcguffin); ! 2368: fprintf(pgpout, LANG("\nEditing userid \"%s\" in key ring: '%s'.\n"), ! 2369: LOCAL_CHARSET((char *) userid), ringfile); ! 2370: ! 2371: if (!file_exists(ringfile)) { ! 2372: fprintf(pgpout, LANG("\nCan't open public key ring file '%s'\n"), ! 2373: ringfile); ! 2374: return -1; ! 2375: } ! 2376: status = getpublickey(GPK_GIVEUP | GPK_SHOW, ringfile, &fpp, &pplength, ! 2377: NULL, (byte *) & timestamp, userid, n, e); ! 2378: if (status < 0) { ! 2379: fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"), ! 2380: ringfile); ! 2381: return -1; ! 2382: } ! 2383: /* Now add to pplength any following key control certificate */ ! 2384: if ((f = fopen(ringfile, FOPRWBIN)) == NULL) { ! 2385: fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"), ! 2386: ringfile); ! 2387: return -1; ! 2388: } ! 2389: if (fread(&ctb, 1, 1, f) != 1 || !is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) { ! 2390: fprintf(pgpout, LANG("\n\007File '%s' is not a public keyring.\n"), ! 2391: ringfile); ! 2392: fclose(f); ! 2393: return -1; ! 2394: } ! 2395: fseek(f, fpp, SEEK_SET); ! 2396: if (is_compromised(f)) { ! 2397: fprintf(pgpout, ! 2398: LANG("\n\007This key has been revoked by its owner.\n")); ! 2399: fclose(f); ! 2400: return -1; ! 2401: } ! 2402: trust_pos = fpp + pplength; ! 2403: fseek(f, trust_pos, SEEK_SET); ! 2404: if (read_trust(f, &keyctrl) < 0) ! 2405: trust_pos = -1; /* keyfile: no trust byte */ ! 2406: ! 2407: extract_keyID(keyID, n); ! 2408: ! 2409: #if 0 ! 2410: /* ! 2411: * Old code: looks in the same directory as the given keyring, but ! 2412: * with the secret keyring filename. ! 2413: */ ! 2414: strcpy(secring, ringfile); ! 2415: strcpy(file_tail(secring), file_tail(globalSecringName)); ! 2416: if (!file_exists(secring) && strcmp(file_tail(secring), "secring.pgp")) { ! 2417: strcpy(file_tail(secring), "secring.pgp"); ! 2418: } ! 2419: #else ! 2420: /* ! 2421: * What it should do: use the secret keyring, always. ! 2422: * Now that the path can be set, this is The Right Thing. ! 2423: * It used to be impossible to put the secret and public keyring in ! 2424: * different directories, so forcing the same directory name was The ! 2425: * Right Thing. It is no longer. ! 2426: */ ! 2427: strcpy(secring, globalSecringName); ! 2428: #endif ! 2429: if (!file_exists(secring)) { ! 2430: fprintf(pgpout, LANG("\nCan't open secret key ring file '%s'\n"), ! 2431: secring); ! 2432: fclose(f); ! 2433: return -1; ! 2434: } ! 2435: /* Get position of key in secret key file */ ! 2436: (void) getpublickey(GPK_GIVEUP | GPK_SECRET, secring, &fps, &pslength, ! 2437: keyID, (byte *) & timestamp, userid1, n, e); ! 2438: /* This was done to get us fps and pslength */ ! 2439: status = getsecretkey(GPK_GIVEUP, secring, keyID, (byte *) & timestamp, ! 2440: ideakey, &hidekey, userid1, n, e, d, p, q, u); ! 2441: ! 2442: if (status < 0) { /* key not in secret keyring: edit owner trust */ ! 2443: int i; ! 2444: ! 2445: fprintf(pgpout, ! 2446: LANG("\nNo secret key available. Editing public key trust parameter.\n")); ! 2447: if (trust_pos < 0) { ! 2448: fprintf(pgpout, ! 2449: LANG("\n\007File '%s' is not a public keyring.\n"), ! 2450: ringfile); ! 2451: fclose(f); ! 2452: return -1; ! 2453: } ! 2454: show_key(f, fpp, SHOW_ALL); ! 2455: ! 2456: init_trust_lst(); ! 2457: fprintf(pgpout, LANG("Current trust for this key's owner is: %s\n"), ! 2458: trust_lst[keyctrl & KC_OWNERTRUST_MASK]); ! 2459: ! 2460: PascalToC((char *) userid); /* convert to C string for display */ ! 2461: i = ask_owntrust((char *) userid, keyctrl); ! 2462: if (i == (keyctrl & KC_OWNERTRUST_MASK)) { ! 2463: fclose(f); ! 2464: return 0; /* unchanged */ ! 2465: } ! 2466: if (i < 0 || i > KC_OWNERTRUST_ALWAYS) { ! 2467: fclose(f); ! 2468: return -1; ! 2469: } ! 2470: keyctrl = (keyctrl & ~KC_OWNERTRUST_MASK) | i; ! 2471: ! 2472: fseek(f, trust_pos, SEEK_SET); ! 2473: write_trust(f, keyctrl); ! 2474: fclose(f); ! 2475: fprintf(pgpout, LANG("Public key ring updated.\n")); ! 2476: return 0; ! 2477: } ! 2478: if (trust_pos > 0 && (keyctrl & (KC_BUCKSTOP | KC_OWNERTRUST_MASK)) != ! 2479: (KC_OWNERTRUST_ULTIMATE | KC_BUCKSTOP)) { ! 2480: /* key is in secret keyring but buckstop is not set */ ! 2481: fprintf(pgpout, ! 2482: LANG("\nUse this key as an ultimately-trusted introducer (y/N)? "), userid); ! 2483: if (getyesno('n')) { ! 2484: fseek(f, trust_pos, SEEK_SET); ! 2485: keyctrl = KC_OWNERTRUST_ULTIMATE | KC_BUCKSTOP; ! 2486: write_trust(f, keyctrl); ! 2487: } ! 2488: } ! 2489: /* Show user her ID again to be clear */ ! 2490: PascalToC((char *) userid); ! 2491: fprintf(pgpout, LANG("\nCurrent user ID: %s"), ! 2492: LOCAL_CHARSET((char *) userid)); ! 2493: CToPascal((char *) userid); ! 2494: ! 2495: fprintf(pgpout, LANG("\nDo you want to add a new user ID (y/N)? ")); ! 2496: if (getyesno('n')) { /* user said yes */ ! 2497: fprintf(pgpout, LANG("\nEnter the new user ID: ")); ! 2498: #ifdef MACTC5 ! 2499: GetNewUID((char *)userid); ! 2500: fprintf(pgpout, "%s\n",userid); ! 2501: #else ! 2502: getstring((char *) userid, 255, TRUE); /* echo keyboard input */ ! 2503: #endif ! 2504: if (userid[0] == '\0') { ! 2505: fclose(f); ! 2506: return -1; ! 2507: } ! 2508: CONVERT_TO_CANONICAL_CHARSET((char *) userid); ! 2509: fprintf(pgpout, ! 2510: LANG("\nMake this user ID the primary user ID for this key (y/N)? ")); ! 2511: if (!getyesno('n')) { ! 2512: /* position file pointer at selected user id */ ! 2513: int pktlen; ! 2514: long fpuser; ! 2515: ! 2516: strcpy((char *) userid1, mcguffin); ! 2517: if (getpubuserid(ringfile, fpp, userid1, &fpuser, &pktlen, ! 2518: FALSE) < 0) { ! 2519: fclose(f); ! 2520: return -1; ! 2521: } ! 2522: fseek(f, fpuser, SEEK_SET); ! 2523: } else { /* position file pointer at key packet */ ! 2524: fseek(f, fpp, SEEK_SET); ! 2525: } ! 2526: nextkeypacket(f, &ctb); /* skip userid or key packet */ ! 2527: do { /* new user id will be inserted before next ! 2528: userid or key packet */ ! 2529: fpu = ftell(f); ! 2530: if (nextkeypacket(f, &ctb) < 0) ! 2531: break; ! 2532: } while (ctb != CTB_USERID && !is_key_ctb(ctb)); ! 2533: CToPascal((char *) userid); /* convert to length-prefixed string */ ! 2534: changeID = TRUE; ! 2535: changed = TRUE; ! 2536: } ! 2537: fclose(f); ! 2538: ! 2539: fprintf(pgpout, LANG("\nDo you want to change your pass phrase (y/N)? ")); ! 2540: if (getyesno('n')) { /* user said yes */ ! 2541: hidekey = (GetHashedPassPhrase((byte *) ideakey, 2) > 0); ! 2542: changed = TRUE; ! 2543: } ! 2544: if (!changed) { ! 2545: fprintf(pgpout, LANG("(No changes will be made.)\n")); ! 2546: if (hidekey) ! 2547: burn(ideakey); ! 2548: goto done; ! 2549: } ! 2550: /* init CFB IDEA key */ ! 2551: if (hidekey) { ! 2552: ideaCfbInit(&cfb, ideakey); ! 2553: burn(ideakey); ! 2554: } ! 2555: /* First write secret key data to a file */ ! 2556: fname = tempfile(TMP_TMPDIR | TMP_WIPE); ! 2557: writekeyfile(fname, hidekey ? &cfb : 0, timestamp, ! 2558: userid, n, e, d, p, q, u); ! 2559: ! 2560: if (hidekey) /* done with IDEA to protect RSA secret key */ ! 2561: ideaCfbDestroy(&cfb); ! 2562: ! 2563: if (changeID) { ! 2564: keylen = -1; ! 2565: } else { ! 2566: /* don't copy userid */ ! 2567: f = fopen(fname, FOPRBIN); ! 2568: if (f == NULL) ! 2569: goto err; ! 2570: nextkeypacket(f, &ctb); /* skip key packet */ ! 2571: keylen = ftell(f); ! 2572: fclose(f); ! 2573: } ! 2574: if (merge_key_to_ringfile(fname, secring, fps, pslength, keylen) < 0) { ! 2575: fprintf(pgpout, LANG("\n\007Unable to update secret key ring.\n")); ! 2576: goto err; ! 2577: } ! 2578: fprintf(pgpout, LANG("\nSecret key ring updated...\n")); ! 2579: #ifdef MACTC5 ! 2580: PGPSetFinfo(secring,'SKey','MPGP'); ! 2581: #endif ! 2582: ! 2583: /* Now write public key data to file */ ! 2584: if (changeID) { ! 2585: if (insert_userid(ringfile, userid, fpu) < 0) { ! 2586: fprintf(pgpout, LANG("\n\007Unable to update public key ring.\n")); ! 2587: goto err; ! 2588: } ! 2589: ! 2590: /* Automatically sign new userid? */ ! 2591: if (sign_new_userids) { ! 2592: PascalToC((char *) userid); ! 2593: strcpy((char *)userid1, (char *)userid); ! 2594: if (do_sign(ringfile, fpp, pplength, userid, keyID, (char *)userid1, TRUE) < 0) ! 2595: return -1; ! 2596: } ! 2597: ! 2598: fprintf(pgpout, LANG("Public key ring updated.\n")); ! 2599: #ifdef MACTC5 ! 2600: PGPSetFinfo(ringfile,'PKey','MPGP'); ! 2601: #endif ! 2602: } else { ! 2603: fprintf(pgpout, LANG("(No need to update public key ring)\n")); ! 2604: } ! 2605: ! 2606: rmtemp(fname); ! 2607: ! 2608: done: ! 2609: mp_burn(d); /* burn sensitive data on stack */ ! 2610: mp_burn(p); ! 2611: mp_burn(q); ! 2612: mp_burn(u); ! 2613: mp_burn(e); ! 2614: mp_burn(n); ! 2615: ! 2616: return 0; /* normal return */ ! 2617: err: ! 2618: mp_burn(d); /* burn sensitive data on stack */ ! 2619: mp_burn(p); ! 2620: mp_burn(q); ! 2621: mp_burn(u); ! 2622: mp_burn(e); ! 2623: mp_burn(n); ! 2624: ! 2625: rmtemp(fname); ! 2626: ! 2627: return -1; /* error return */ ! 2628: ! 2629: } /* dokeyedit */ ! 2630: ! 2631: int disable_key(char *keyguffin, char *keyfile) ! 2632: { ! 2633: FILE *f; ! 2634: byte keyctrl; ! 2635: byte keyID[KEYFRAGSIZE]; ! 2636: byte userid[256]; ! 2637: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 2638: long fp; ! 2639: int pktlen; ! 2640: ! 2641: strcpy((char *) userid, keyguffin); ! 2642: if (getpublickey(GPK_SHOW | GPK_DISABLED, keyfile, &fp, &pktlen, NULL, ! 2643: NULL, userid, n, e) < 0) ! 2644: return -1; ! 2645: ! 2646: extract_keyID(keyID, n); ! 2647: if (getsecretkey(GPK_GIVEUP, NULL, keyID, NULL, NULL, NULL, ! 2648: userid, n, e, NULL, NULL, NULL, NULL) >= 0) { ! 2649: /* can only compromise if key also in secring */ ! 2650: PascalToC((char *) userid); ! 2651: fprintf(pgpout, ! 2652: LANG("\nDo you want to permanently revoke your public key\n\ ! 2653: by issuing a secret key compromise certificate\n\ ! 2654: for \"%s\" (y/N)? "), LOCAL_CHARSET((char *) userid)); ! 2655: if (getyesno('n')) ! 2656: return compromise(keyID, keyfile); ! 2657: } ! 2658: if ((f = fopen(keyfile, FOPRWBIN)) == NULL) { ! 2659: fprintf(pgpout, ! 2660: LANG("\n\007Can't open key ring file '%s'\n"), keyfile); ! 2661: return -1; ! 2662: } ! 2663: fseek(f, fp + pktlen, SEEK_SET); ! 2664: if (read_trust(f, &keyctrl) < 0) { ! 2665: fprintf(pgpout, ! 2666: LANG("\n\007File '%s' is not a public keyring.\n"), keyfile); ! 2667: fprintf(pgpout, ! 2668: LANG("You can only disable keys on your public keyring.\n")); ! 2669: fclose(f); ! 2670: return -1; ! 2671: } ! 2672: if (keyctrl & KC_DISABLED) { ! 2673: fprintf(pgpout, LANG("\nKey is already disabled.\n\ ! 2674: Do you want to enable this key again (y/N)? ")); ! 2675: keyctrl &= ~KC_DISABLED; ! 2676: } else { ! 2677: fprintf(pgpout, LANG("\nDisable this key (y/N)? ")); ! 2678: keyctrl |= KC_DISABLED; ! 2679: } ! 2680: if (!getyesno('n')) { ! 2681: fclose(f); ! 2682: return -1; ! 2683: } ! 2684: write_trust_pos(f, keyctrl, fp + pktlen); ! 2685: fclose(f); ! 2686: return 0; ! 2687: } /* disable_key */ ! 2688: ! 2689: ! 2690: /*======================================================================*/ ! 2691: ! 2692: /* ! 2693: * Do an RSA key pair generation, and write them out to the keyring files. ! 2694: * numstr is a decimal string, the desired bitcount for the modulus n. ! 2695: * numstr2 is a decimal string, the desired bitcount for the exponent e. ! 2696: * username is the desired name for the key. ! 2697: */ ! 2698: int dokeygen(char *numstr, char *numstr2, char *username) ! 2699: { ! 2700: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 2701: unit d[MAX_UNIT_PRECISION], p[MAX_UNIT_PRECISION]; ! 2702: unit q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION]; ! 2703: char *fname; ! 2704: #ifdef MACTC5 ! 2705: char message[256]; ! 2706: #endif ! 2707: word16 iv[4]; /* for IDEA CFB mode, to protect ! 2708: RSA secret key */ ! 2709: byte userid[256]; ! 2710: short keybits, ebits; ! 2711: word32 tstamp; ! 2712: boolean hidekey; /* TRUE iff secret key is encrypted */ ! 2713: boolean cryptrandflag; ! 2714: byte ideakey[16]; ! 2715: struct IdeaCfbContext cfb; ! 2716: struct hashedpw *hpw; ! 2717: byte keyID[KEYFRAGSIZE]; ! 2718: boolean keygen_OK; ! 2719: ! 2720: if (!numstr || strlen(numstr) == 0) { ! 2721: #ifdef MACTC5 ! 2722: numstr = (char *)userid; ! 2723: if (argc < 5) getRSAkeySize(numstr,numstr2); ! 2724: #endif ! 2725: fputs("\n", pgpout); ! 2726: fputs(LANG("Pick your RSA key size:\n\ ! 2727: 1) 512 bits- Low commercial grade, fast but less secure\n\ ! 2728: 2) 768 bits- High commercial grade, medium speed, good security\n\ ! 2729: 3) 1024 bits- \"Military\" grade, slow, highest security\n\ ! 2730: Choose 1, 2, or 3, or enter desired number of bits: "), pgpout); ! 2731: #ifdef MACTC5 ! 2732: fprintf(pgpout, "%s\n",numstr); ! 2733: #else ! 2734: numstr = (char *) userid; /* use userid buffer as scratchpad */ ! 2735: getstring(numstr, 5, TRUE); /* echo keyboard */ ! 2736: #endif ! 2737: } ! 2738: #ifdef MACTC5 ! 2739: else /* CP: argv[4] contains the new_userid */ ! 2740: if(argc>4) ! 2741: strcpy(new_uid,argv[4]); ! 2742: #endif ! 2743: keybits = 0; ! 2744: while ((*numstr >= '0') && (*numstr <= '9')) ! 2745: keybits = keybits * 10 + (*numstr++ - '0'); ! 2746: ! 2747: if (keybits == 0) /* user entered null response */ ! 2748: return -1; /* error return */ ! 2749: ! 2750: /* Standard default key sizes: */ ! 2751: if (keybits == 1) ! 2752: keybits = 512; /* Low commercial grade */ ! 2753: if (keybits == 2) ! 2754: keybits = 768; /* High commercial grade */ ! 2755: if (keybits == 3) ! 2756: keybits = 1024; /* Military grade */ ! 2757: ! 2758: #ifndef DEBUG ! 2759: if (keybits < MIN_KEY_BITS) ! 2760: keybits = MIN_KEY_BITS; ! 2761: if (keybits > MAX_KEY_BITS) ! 2762: keybits = MAX_KEY_BITS; ! 2763: #else ! 2764: if (keybits > MAX_BIT_PRECISION) ! 2765: keybits = MAX_BIT_PRECISION; ! 2766: #endif ! 2767: ! 2768: ebits = 0; /* number of bits in e */ ! 2769: while ((*numstr2 >= '0') && (*numstr2 <= '9')) ! 2770: ebits = ebits * 10 + (*numstr2++ - '0'); ! 2771: ! 2772: fprintf(pgpout, "\n"); ! 2773: fprintf(pgpout, ! 2774: LANG("Generating an RSA key with a %d-bit modulus.\n"), keybits); ! 2775: ! 2776: if (username == NULL || *username == '\0') { ! 2777: /* We need to ask for a username */ ! 2778: fputs( ! 2779: LANG("\nYou need a user ID for your public key. The desired form for this\n\ ! 2780: user ID is your name, followed by your E-mail address enclosed in\n\ ! 2781: <angle brackets>, if you have an E-mail address.\n\ ! 2782: For example: John Q. Smith <[email protected]>\n\ ! 2783: Enter a user ID for your public key: \n"), pgpout); ! 2784: #ifdef VMS ! 2785: putch('\n'); /* That last newline was just a return, do a real one */ ! 2786: #endif ! 2787: #ifdef MACTC5 ! 2788: strcpy((char *)userid,new_uid); ! 2789: fprintf(stdout, "%s\n",new_uid); ! 2790: #else ! 2791: getstring((char *) userid, 255, TRUE); /* echo keyboard input */ ! 2792: #endif ! 2793: if (userid[0] == '\0') /* user entered null response */ ! 2794: return -1; /* error return */ ! 2795: ! 2796: } else { ! 2797: /* Copy in passed-in username */ ! 2798: memcpy(userid, username, 255); ! 2799: fprintf(pgpout, ! 2800: LANG("Generating RSA key-pair with UserID \"%s\".\n"), userid); ! 2801: } ! 2802: CONVERT_TO_CANONICAL_CHARSET((char *) userid); ! 2803: CToPascal((char *) userid); /* convert to length-prefixed string */ ! 2804: ! 2805: fputs(LANG("\nYou need a pass phrase to protect your RSA secret key.\n\ ! 2806: Your pass phrase can be any sentence or phrase and may have many\n\ ! 2807: words, spaces, punctuation, or any other printable characters.\n"), pgpout); ! 2808: hidekey = (GetHashedPassPhrase(ideakey, 2) > 0); ! 2809: /* init CFB IDEA key */ ! 2810: #ifdef MACTC5 ! 2811: if (Abort) ! 2812: exitPGP(-2); ! 2813: #endif ! 2814: if (hidekey) { ! 2815: /* Remember password - we need it later when we sign the key */ ! 2816: hpw = (struct hashedpw *) malloc(sizeof(struct hashedpw)); ! 2817: if (hpw) { ! 2818: /* If malloc fails, just don't remember the phrase */ ! 2819: memcpy(hpw->hash, ideakey, sizeof(hpw->hash)); ! 2820: hpw->next = keypasswds; ! 2821: keypasswds = hpw; ! 2822: } ! 2823: ideaCfbInit(&cfb, ideakey); ! 2824: trueRandAccumLater(64); /* IV for encryption */ ! 2825: } ! 2826: /* As rsa_keygen does a major accumulation of random bits, if we need ! 2827: * any others for a seed file, let's get them at the same time. ! 2828: */ ! 2829: cryptrandflag = (cryptRandOpen((struct IdeaCfbContext *)0) < 0); ! 2830: if (cryptrandflag) ! 2831: trueRandAccumLater(192); ! 2832: ! 2833: fputs(LANG("\nNote that key generation is a lengthy process.\n"), pgpout); ! 2834: ! 2835: #ifdef MACTC5 ! 2836: InitCursor(); ! 2837: strcpy(message,"Now generating RSA key pair.\rType command-period to abort."); ! 2838: c2pstr(message); ! 2839: ParamText((uchar *)message,(uchar *)"",(uchar *)"",(uchar *)""); ! 2840: ProgressDialog=GetNewDialog(161,nil,(WindowPtr)-1); ! 2841: #endif ! 2842: ! 2843: if (rsa_keygen(n, e, d, p, q, u, keybits, ebits) < 0) { ! 2844: #ifdef MACTC5 ! 2845: if (Abort) ! 2846: fprintf(pgpout, LANG("Key generation stopped at user request.\n")); ! 2847: else ! 2848: fprintf(pgpout, LANG("\n\007Keygen failed!\n")); ! 2849: DisposDialog(ProgressDialog); ! 2850: ProgressDialog=NULL; ! 2851: return -1; /* error return */ ! 2852: } ! 2853: DisposDialog(ProgressDialog); ! 2854: ProgressDialog=NULL; ! 2855: #else ! 2856: fputs(LANG("\n\007Keygen failed!\n"), pgpout); ! 2857: return -1; /* error return */ ! 2858: } ! 2859: #endif ! 2860: putc('\n', pgpout); ! 2861: ! 2862: if (verbose) { ! 2863: fprintf(pgpout, LANG("Key ID %s\n"), key2IDstring(n)); ! 2864: ! 2865: mp_display(" modulus n = ", n); ! 2866: mp_display("exponent e = ", e); ! 2867: ! 2868: fputs(LANG("Display secret components (y/N)?"), pgpout); ! 2869: if (getyesno('n')) { ! 2870: mp_display("exponent d = ", d); ! 2871: mp_display(" prime p = ", p); ! 2872: mp_display(" prime q = ", q); ! 2873: mp_display(" inverse u = ", u); ! 2874: } ! 2875: } ! 2876: tstamp = get_timestamp(NULL); /* Timestamp when key was generated */ ! 2877: ! 2878: fputc('\007', pgpout); /* sound the bell when done with lengthy process */ ! 2879: fflush(pgpout); ! 2880: ! 2881: /* First, write out the secret key... */ ! 2882: fname = tempfile(TMP_TMPDIR | TMP_WIPE); ! 2883: writekeyfile(fname, hidekey ? &cfb : 0, tstamp, userid, n, e, d, p, q, u); ! 2884: ! 2885: mp_burn(d); ! 2886: mp_burn(p); ! 2887: mp_burn(q); ! 2888: mp_burn(u); ! 2889: ! 2890: if (hidekey) /* done with IDEA to protect RSA secret key */ ! 2891: ideaCfbDestroy(&cfb); ! 2892: ! 2893: if (file_exists(globalSecringName)) { ! 2894: if (!(keygen_OK = (merge_key_to_ringfile(fname, globalSecringName, 0L, 0, -1L) == 0))) ! 2895: fprintf(pgpout, LANG("\n\007Unable to update secret key ring.\n")); ! 2896: rmtemp(fname); ! 2897: } else { ! 2898: keygen_OK = (savetemp(fname, globalSecringName) != NULL); ! 2899: } ! 2900: ! 2901: /* Second, write out the public key... */ ! 2902: if (keygen_OK) { ! 2903: fname = tempfile(TMP_TMPDIR | TMP_WIPE); ! 2904: writekeyfile(fname, NULL, tstamp, userid, n, e, NULL, NULL, NULL, NULL); ! 2905: if (file_exists(globalPubringName)) { ! 2906: if (!(keygen_OK = (merge_key_to_ringfile(fname, globalPubringName, 0L, 0, -1L) == 0))) ! 2907: fprintf(pgpout, LANG("\n\007Unable to update public key ring.\n")); ! 2908: rmtemp(fname); ! 2909: } else { ! 2910: keygen_OK = (savetemp(fname, globalPubringName) != NULL); ! 2911: } ! 2912: } ! 2913: ! 2914: /* Finally, sign the newly created userid on the public key... */ ! 2915: if (keygen_OK && sign_new_userids) { ! 2916: long fp; ! 2917: int pktlen; ! 2918: word32 tstamp; byte *timestamp = (byte *) &tstamp; ! 2919: byte sigguffin[256]; ! 2920: ! 2921: PascalToC((char *) userid); ! 2922: extract_keyID(keyID, n); ! 2923: getpublickey(GPK_GIVEUP, globalPubringName, &fp, &pktlen, NULL, ! 2924: timestamp, userid, n, e); ! 2925: PascalToC((char *) userid); ! 2926: strcpy((char *)sigguffin, (char *)userid); ! 2927: do_sign(globalPubringName, fp, pktlen, userid, keyID, (char *)sigguffin, TRUE); ! 2928: } ! 2929: ! 2930: mp_burn(e); ! 2931: mp_burn(n); ! 2932: ! 2933: if (keygen_OK) ! 2934: fputs(LANG("\007Key generation completed.\n"), pgpout); ! 2935: else ! 2936: return -1; /* error return */ ! 2937: ! 2938: /* ! 2939: * If we need a seed file, create it now. ! 2940: */ ! 2941: if (cryptrandflag) { ! 2942: trueRandConsume(192); ! 2943: cryptRandInit((struct IdeaCfbContext *)0); ! 2944: /* It will get saved by exitPGP */ ! 2945: } ! 2946: return 0; /* normal return */ ! 2947: } /* dokeygen */ ! 2948: ! 2949: /* Does double duty for both -kv[v] and -kxa */ ! 2950: void kv_title(FILE *fo) ! 2951: { ! 2952: fprintf(fo, LANG("Type Bits/KeyID Date User ID\n")); ! 2953: return; ! 2954: } /* kv_title */ ! 2955: ! 2956: /* Does double duty for both -kv[v] and -kxa */ ! 2957: /* returns status & keycounter*/ ! 2958: int kvformat_keypacket(FILE *f, FILE *pgpout, boolean one_key, ! 2959: char *mcguffin, char *ringfile, ! 2960: boolean show_signatures, boolean show_hashes, ! 2961: int *keycounter) ! 2962: { ! 2963: byte ctb, keyctb=0; ! 2964: int status; ! 2965: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 2966: byte keyID[KEYFRAGSIZE]; ! 2967: byte sigkeyID[KEYFRAGSIZE]; ! 2968: byte userid[256]; /* key certificate userid */ ! 2969: char *siguserid; /* signator userid */ ! 2970: word32 tstamp; ! 2971: byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ ! 2972: int firstuser = 0; ! 2973: int compromised = 0; ! 2974: boolean shownKeyHash=FALSE; ! 2975: boolean invalid_key=FALSE; /* unsupported version or bad data */ ! 2976: boolean match = FALSE; ! 2977: boolean disabled = FALSE; ! 2978: boolean first_key= FALSE; ! 2979: ! 2980: for (;;) { ! 2981: status = readkeypacket(f, FALSE, &ctb, timestamp, (char *) userid, ! 2982: n, e, ! 2983: NULL, NULL, NULL, NULL, sigkeyID, NULL); ! 2984: /* Note that readkeypacket has called set_precision */ ! 2985: if (status == -1) { ! 2986: status = 0; ! 2987: break; /* eof reached */ ! 2988: } ! 2989: if (status == -4 || status == -6) { ! 2990: /* only ctb and userid are valid */ ! 2991: memset(sigkeyID, 0, KEYFRAGSIZE); ! 2992: tstamp = 0; ! 2993: } else if (status < 0) { ! 2994: fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"), ! 2995: ringfile); ! 2996: break; ! 2997: } ! 2998: if (is_key_ctb(ctb)) { ! 2999: byte keyctrl; ! 3000: ! 3001: firstuser = 1; ! 3002: keyctb = ctb; ! 3003: compromised = is_compromised(f); ! 3004: shownKeyHash = FALSE; ! 3005: if (status < 0) { ! 3006: invalid_key = TRUE; ! 3007: memset(keyID, 0, KEYFRAGSIZE); ! 3008: } else { ! 3009: invalid_key = FALSE; ! 3010: extract_keyID(keyID, n); ! 3011: if (read_trust(f, &keyctrl) == 0 && (keyctrl & KC_DISABLED)) ! 3012: disabled = TRUE; ! 3013: else ! 3014: disabled = FALSE; ! 3015: } ! 3016: } ! 3017: if (ctb != CTB_USERID && !is_ctb_type(ctb, CTB_SKE_TYPE)) ! 3018: continue; ! 3019: if (ctb == CTB_USERID) { ! 3020: PascalToC((char *) userid); ! 3021: match = userid_match((char *) userid, mcguffin, n); ! 3022: } ! 3023: if (match) { ! 3024: if (ctb == CTB_USERID) { ! 3025: if (firstuser) { ! 3026: (*keycounter)++; ! 3027: if (is_ctb_type(keyctb, CTB_CERT_PUBKEY_TYPE)) ! 3028: fprintf(pgpout, LANG("pub")); ! 3029: else if (is_ctb_type(keyctb, CTB_CERT_SECKEY_TYPE)) ! 3030: fprintf(pgpout, LANG("sec")); ! 3031: else ! 3032: fprintf(pgpout, "???"); ! 3033: if (invalid_key) ! 3034: fprintf(pgpout, "? "); ! 3035: else if (disabled) ! 3036: fprintf(pgpout, "- "); ! 3037: else ! 3038: fprintf(pgpout, " "); ! 3039: fprintf(pgpout, "%4d/%s %s ", ! 3040: countbits(n), keyIDstring(keyID), cdate(&tstamp)); ! 3041: } else { ! 3042: fprintf(pgpout, " %s ", blankkeyID); ! 3043: } ! 3044: if (compromised && firstuser) { ! 3045: fprintf(pgpout, LANG("*** KEY REVOKED ***\n")); ! 3046: fprintf(pgpout, " %s ", blankkeyID); ! 3047: } ! 3048: firstuser = 0; ! 3049: fprintf(pgpout, "%s\n", LOCAL_CHARSET((char *) userid)); ! 3050: ! 3051: /* Display the hashes for n and e if required */ ! 3052: if (show_hashes && !shownKeyHash) { ! 3053: showKeyHash(n, e); ! 3054: shownKeyHash = TRUE; ! 3055: } ! 3056: } else if (show_signatures && ! 3057: !(firstuser && compromised)) { ! 3058: /* Must be sig cert */ ! 3059: fprintf(pgpout, LANG("sig")); ! 3060: fprintf(pgpout, "%c ", status < 0 ? '?' : ' '); ! 3061: showkeyID(sigkeyID, pgpout); ! 3062: fprintf(pgpout, " "); /* Indent signator userid */ ! 3063: if ((siguserid = user_from_keyID(sigkeyID)) == NULL) ! 3064: fprintf(pgpout, ! 3065: LANG("(Unknown signator, can't be checked)\n")); ! 3066: else ! 3067: fprintf(pgpout, "%s\n", LOCAL_CHARSET(siguserid)); ! 3068: } /* printing a sig cert */ ! 3069: } /* if it has mcguffin */ ! 3070: } /* loop for all packets */ ! 3071: return(status); ! 3072: } /* kvformat_keypacket */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.