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

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

unix.superglobalmegacorp.com

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