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