home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1998 February / PCOnline_02_1998.iso / filesbbs / os2 / pgp263.arj / PGP263I.SRC / PGP263II.ZIP / src / keymgmt.c < prev    next >
C/C++ Source or Header  |  1996-01-08  |  95KB  |  3,073 lines

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