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

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

unix.superglobalmegacorp.com

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