Annotation of pgp/src/keymgmt.c, revision 1.1.1.9

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.