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