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