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

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

unix.superglobalmegacorp.com

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