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

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

unix.superglobalmegacorp.com

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