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

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) &&
1.1.1.8 ! root      677:                (is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE) ||
        !           678:                 is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) &&
1.1.1.7   root      679:                read_trust(f, &keyctrl) == 0 &&
                    680:                (keyctrl & KC_DISABLED))
                    681:                skip = TRUE;
                    682:            else
                    683:                skip = FALSE;
                    684:        }
                    685:        /* Only check for matches when we find a USERID packet */
                    686:        if (!skip && ctb == CTB_USERID) {
                    687:   /* keyID contains key fragment.  Check it against n from keyfile. */
                    688:            if (keyID != NULL) {
                    689:                if (keystatus == 0)
                    690:                    keyfound = checkkeyID(keyID, n);
                    691:            } else {
                    692:                /* matchid is already a C string */
                    693:                PascalToC((char *) userid);     /* for C string functions */
                    694:                /* Accept any matching subset */
                    695:                keyfound = userid_match((char *) userid, matchid, n);
                    696:                CToPascal((char *) userid);
                    697:            }
                    698:        }
                    699:        if (keyfound) {
                    700:            if (flags & GPK_SHOW)
                    701:                show_key(f, file_position, 0);
                    702:            fseek(f, file_position, SEEK_SET);
                    703:            if ((flags & GPK_NORVK) && keystatus == 0 && is_compromised(f)) {
                    704:                if (flags & GPK_SHOW) {         /* already printed user ID */
                    705:                    fprintf(pgpout,
                    706:               LANG("\n\007Sorry, this key has been revoked by its owner.\n"));
                    707:                } else {
                    708:                    PascalToC((char *) userid);
                    709:                    fprintf(pgpout, LANG("\nKey for user ID \"%s\"\n\
                    710: has been revoked.  You cannot use this key.\n"),
                    711:                            LOCAL_CHARSET((char *) userid));
                    712:                }
                    713:                keyfound = FALSE;
                    714:                skip = TRUE;
                    715:                /* we're positioned at the key packet, skip it */
                    716:                nextkeypacket(f, &ctb);
                    717:            } else {
                    718:                /* found key, normal return */
                    719:                if (_pktlen)
                    720:                    *_pktlen = pktlen;
                    721:                if (_file_position)
                    722:                    *_file_position = file_position;
                    723:                fclose(f);
                    724:                return keystatus;
                    725:            }
1.1.1.6   root      726:        }
1.1.1.7   root      727:     }                          /* while TRUE */
1.1.1.6   root      728: 
1.1.1.7   root      729:     fclose(f);                 /* close key file */
1.1.1.6   root      730: 
1.1.1.7   root      731:     if (flags & GPK_GIVEUP)
                    732:        return -1;              /* give up, error return */
                    733: 
                    734:     if (keyID != NULL) {
                    735:        fprintf(pgpout,
                    736:        LANG("\n\007Key matching expected Key ID %s not found in file '%s'.\n"),
                    737:                keyIDstring(keyID), keyfile);
                    738:     } else {
                    739:        fprintf(pgpout,
                    740:            LANG("\n\007Key matching userid '%s' not found in file '%s'.\n"),
                    741:                LOCAL_CHARSET(matchid), keyfile);
                    742:     }
                    743: 
                    744:   nogood:
                    745:     if (filter_mode || batchmode)
                    746:        return -1;              /* give up, error return */
                    747: 
                    748:     if (flags & GPK_SECRET)
                    749:        fprintf(pgpout, LANG("Enter secret key filename: "));
                    750:     else
                    751:        fprintf(pgpout, LANG("Enter public key filename: "));
1.1.1.6   root      752: 
1.1.1.7   root      753:     getstring(keyfile, 59, TRUE);      /* echo keyboard input */
                    754:     goto top;
1.1.1.6   root      755: 
1.1.1.7   root      756: }                              /* getpublickey */
1.1.1.6   root      757: 
                    758: /*  Start at key_position in keyfile, and scan for the key packet
1.1.1.7   root      759:    that contains userid.  Return userid_position and userid_len.
                    760:    Return 0 if OK, -1 on error.  Userid should be a C string.
                    761:    If exact_match is TRUE, the userid must match for full length,
                    762:    a substring is not enough.
                    763:  */
                    764: int getpubuserid(char *keyfile, long key_position, byte * userid,
                    765:             long *userid_position, int *userid_len, boolean exact_match)
                    766: {
                    767:     unit n[MAX_UNIT_PRECISION];
                    768:     unit e[MAX_UNIT_PRECISION];
                    769:     byte ctb;                  /* returned by readkeypacket */
                    770:     FILE *f;
                    771:     int status;
                    772:     char userid0[256];         /* C string format */
                    773:     long fpos;
                    774: 
                    775:     /* open file f for read, in binary (not text) mode... */
                    776:     if ((f = fopen(keyfile, FOPRBIN)) == NULL)
                    777:        return -1;              /* error return */
                    778: 
                    779:     /* Start off at correct location */
                    780:     fseek(f, key_position, SEEK_SET);
                    781:     (void) nextkeypacket(f, &ctb);     /* Skip key */
                    782:     for (;;) {
                    783:        fpos = ftell(f);
                    784:        status = readkeypacket(f, FALSE, &ctb, NULL, (char *) userid0, n, e,
                    785:                               NULL, NULL, NULL, NULL, NULL, NULL);
                    786: 
                    787:        if (status < 0 || is_key_ctb(ctb)) {
                    788:            fclose(f);          /* close key file */
                    789:            return status ? status : -1;        /* give up, error return */
                    790:        }
                    791:        /* Only check for matches when we find a USERID packet */
                    792:        if (ctb == CTB_USERID) {
                    793:            if (userid[0] == '0' && userid[1] == 'x')
                    794:                break;         /* use first userid if user specified a keyID */
                    795:            /* userid is already a C string */
                    796:            PascalToC((char *) userid0);        /* for C string functions */
                    797:            /* Accept any matching subset if exact_match is FALSE */
                    798:            if (userid_match((char *) userid0, (char *) userid,
                    799:                             (exact_match ? NULL : n)))
                    800:                break;
                    801:        }
                    802:     }                          /* for(;;) */
                    803:     *userid_position = fpos;
                    804:     *userid_len = (int) (ftell(f) - fpos);
                    805:     fclose(f);
                    806:     return 0;                  /* normal return */
                    807: }                              /* getpubuserid */
1.1.1.6   root      808: 
                    809: /*
                    810:  * Start at user_position in keyfile, and scan for the signature packet
                    811:  * that matches sigkeyID.  Return the signature timestamp, sig_position
                    812:  * and sig_len.
                    813:  *
                    814:  * Return 0 if OK, -1 on error.
                    815:  */
1.1.1.7   root      816: int getpubusersig(char *keyfile, long user_position, byte * sigkeyID,
                    817:                  byte * timestamp, long *sig_position, int *sig_len)
1.1.1.6   root      818: {
1.1.1.7   root      819:     byte ctb;                  /* returned by readkeypacket */
                    820:     FILE *f;
                    821:     int status;
                    822:     byte keyID0[KEYFRAGSIZE];
                    823:     long fpos;
                    824: 
                    825:     /* open file f for read, in binary (not text) mode... */
                    826:     if ((f = fopen(keyfile, FOPRBIN)) == NULL)
                    827:        return -1;              /* error return */
                    828: 
                    829:     /* Start off at correct location */
                    830:     fseek(f, user_position, SEEK_SET);
                    831:     (void) nextkeypacket(f, &ctb);     /* Skip userid packet */
                    832:     for (;;) {
                    833:        fpos = ftell(f);
                    834:        status = readkeypacket(f, FALSE, &ctb, NULL, NULL, NULL, NULL,
                    835:                               NULL, NULL, NULL, NULL, keyID0, NULL);
1.1.1.6   root      836: 
1.1.1.7   root      837:        if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID)
                    838:            break;
                    839: 
                    840:        /* Only check for matches when we find a signature packet */
                    841:        if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
                    842:            if (equal_buffers(sigkeyID, keyID0, KEYFRAGSIZE)) {
                    843:                *sig_position = fpos;
                    844:                *sig_len = (int) (ftell(f) - fpos);
                    845:                fseek(f, fpos + 6, SEEK_SET);
                    846:                fread(timestamp, 1, SIZEOF_TIMESTAMP, f); /* read certificate
                    847:                                                             timestamp */
                    848:                convert_byteorder(timestamp, SIZEOF_TIMESTAMP); /* convert
                    849:                                                               from external 
                    850:                                                               orm */
                    851:                fclose(f);
                    852:                return 0;       /* normal return */
                    853:            }
                    854:        }
                    855:     }                          /* for (;;) */
1.1.1.6   root      856: 
1.1.1.7   root      857:     fclose(f);                 /* close key file */
                    858:     return status ? status : -1;       /* give up, error return */
                    859: }                              /* getpubusersig */
1.1.1.6   root      860: 
                    861: /*
                    862:  * keyID contains key fragment we expect to find in keyfile.
                    863:  * If keyID is NULL, then userid contains search target of
                    864:  * userid to find in keyfile.
                    865:  * giveup controls whether we ask the user for the name of the
                    866:  * secret key file on failure.  showkey controls whether we print
                    867:  * out the key information when we find it.  keyfile, if non-NULL,
                    868:  * is the name of the secret key file; if NULL, we use the
                    869:  * default.  hpass and hkey, if non-NULL, get returned with a copy
                    870:  * of the hashed password buffer and hidekey variable.
                    871:  */
1.1.1.7   root      872: int getsecretkey(int flags, char *keyfile, byte * keyID,
                    873:           byte * timestamp, byte * hpass, boolean * hkey, byte * userid,
                    874:                 unitptr n, unitptr e, unitptr d, unitptr p, unitptr q,
                    875:                 unitptr u)
                    876: {
                    877:     byte ctb;                  /* returned by readkeypacket */
                    878:     FILE *f;
                    879:     char keyfilename[MAX_PATH];        /* for getpublickey */
                    880:     long file_position;
                    881:     int status;
                    882:     boolean hidekey;           /* TRUE iff secret key is encrypted */
                    883:     word16 iv[4];              /* initialization vector for encryption */
                    884:     byte ideakey[16];
                    885:     int guesses;
                    886:     struct hashedpw *hpw, **hpwp;
                    887:     struct IdeaCfbContext cfb;
                    888: 
                    889:     if (keyfile == NULL) {
                    890:        /* use default pathname */
                    891:        strcpy(keyfilename, globalSecringName);
                    892:        keyfile = keyfilename;
                    893:     }
                    894:     status = getpublickey(flags | GPK_SECRET, keyfile, &file_position,
                    895:                          NULL, keyID, timestamp, userid, n, e);
                    896:     if (status < 0)
                    897:        return status;          /* error return */
                    898: 
                    899:     /* open file f for read, in binary (not text) mode... */
                    900:     if ((f = fopen(keyfile, FOPRBIN)) == NULL)
                    901:        return -1;              /* error return */
                    902: 
                    903:     /* First guess is no password */
                    904:     hidekey = FALSE;
                    905:     fseek(f, file_position, SEEK_SET); /* reposition file to key */
                    906:     status = readkeypacket(f, 0, &ctb, timestamp, (char *) userid,
                    907:                           n, e, d, p, q, u, NULL, NULL);
                    908:     if (status != -5)          /* Anything except bad password */
                    909:        goto done;
                    910: 
                    911:     /* If we're not signing a key (when we force asking the user),
                    912:      * check the prevosuly known passwords.
                    913:      */
                    914:     if (!(flags & GPK_ASKPASS)) {
                    915:        hidekey = TRUE;
                    916:        /* Then come existing key passwords */
                    917:        hpw = keypasswds;
                    918:        while (hpw) {
                    919:            ideaCfbInit(&cfb, hpw->hash);
                    920:            fseek(f, file_position, SEEK_SET);
                    921:            status = readkeypacket(f, &cfb, &ctb, timestamp,
                    922:                          (char *) userid, n, e, d, p, q, u, NULL, NULL);
                    923:            ideaCfbDestroy(&cfb);
                    924:            if (status != -5) {
                    925:                memcpy(ideakey, hpw->hash, sizeof(ideakey));
1.1.1.6   root      926:                goto done;
1.1.1.7   root      927:            }
                    928:            hpw = hpw->next;
                    929:        }
                    930:        /* Then try "other" passwords" */
                    931:        hpwp = &passwds;
                    932:        hpw = *hpwp;
                    933:        while (hpw) {
                    934:            ideaCfbInit(&cfb, hpw->hash);
                    935:            fseek(f, file_position, SEEK_SET);
                    936:            status = readkeypacket(f, &cfb, &ctb, timestamp,
                    937:                          (char *) userid, n, e, d, p, q, u, NULL, NULL);
                    938:            ideaCfbDestroy(&cfb);
                    939:            if (status >= 0) {
                    940:                /* Success - move to key password list */
                    941:                memcpy(ideakey, hpw->hash, sizeof(ideakey));
                    942:                *hpwp = hpw->next;
                    943:                hpw->next = keypasswds;
                    944:                keypasswds = hpw;
                    945:            }
                    946:            if (status != -5)
                    947:                goto done;
                    948:            hpwp = &hpw->next;
                    949:            hpw = *hpwp;
                    950:        }
                    951:     }
                    952:     /* If batchmode, we don't ask the user. */
                    953:     if (batchmode) {
                    954:        /* PGPPASS (or -z) wrong or not set */
                    955:        fprintf(pgpout, LANG("\n\007Error:  Bad pass phrase.\n"));
                    956:        fclose(f);              /* close key file */
                    957:        return -1;
                    958:     }
                    959:     /* Finally, prompt the user. */
                    960:     fprintf(pgpout,
                    961:            LANG("\nYou need a pass phrase to unlock your RSA secret key. "));
                    962:     if (!(flags & GPK_SHOW)) {
                    963:        /* let user know for which key he should type his password */
                    964:        PascalToC((char *) userid);
                    965:        fprintf(pgpout, LANG("\nKey for user ID \"%s\"\n"),
                    966:                LOCAL_CHARSET((char *) userid));
                    967:        CToPascal((char *) userid);
                    968:     }
                    969:     guesses = 0;
                    970:     for (;;) {
                    971:        if (++guesses > 3)
                    972:            hidekey = 0;
                    973:        else
                    974:            hidekey = (GetHashedPassPhrase(ideakey, 1) > 0);
                    975:        /*
                    976:         * We've already tried the null password - interpret
                    977:         * a null string as "I dunno".
1.1.1.6   root      978:         */
1.1.1.7   root      979:        if (!hidekey) {
                    980:            status = -5;        /* Bad passphrase */
                    981:            fputs(LANG("No passphrase; secret key unavailable.\n"),
                    982:                  pgpout);
                    983:            break;
                    984:        }
                    985:        ideaCfbInit(&cfb, ideakey);
                    986:        fseek(f, file_position, SEEK_SET);
                    987:        status = readkeypacket(f, &cfb, &ctb, timestamp,
                    988:                          (char *) userid, n, e, d, p, q, u, NULL, NULL);
                    989:        ideaCfbDestroy(&cfb);
                    990:        if (status >= 0) {
                    991:            /* Success - remember this key for later use */
                    992:            if (flags & GPK_ASKPASS) {
                    993:                /*
                    994:                 * This may be a duplicate because we didn't
                    995:                 * search the lists before - check.
                    996:                 */
                    997:                hpw = passwds;
1.1.1.6   root      998:                while (hpw) {
1.1.1.7   root      999:                    if (memcmp(hpw->hash, ideakey,
                   1000:                               sizeof(ideakey)) == 0)
                   1001:                        goto done;
                   1002:                    hpw = hpw->next;
1.1.1.6   root     1003:                }
1.1.1.7   root     1004:                hpw = keypasswds;
1.1.1.6   root     1005:                while (hpw) {
1.1.1.7   root     1006:                    if (memcmp(hpw->hash, ideakey,
                   1007:                               sizeof(ideakey)) == 0)
1.1.1.6   root     1008:                        goto done;
1.1.1.7   root     1009:                    hpw = hpw->next;
1.1.1.6   root     1010:                }
1.1.1.7   root     1011:            }
                   1012:            /* Insert new key into remember lists. */
                   1013:            hpw = (struct hashedpw *) malloc(sizeof(struct hashedpw));
                   1014:            if (hpw) {
                   1015:                /* If malloc fails, just don't remember the phrase */
                   1016:                memcpy(hpw->hash, ideakey, sizeof(hpw->hash));
                   1017:                hpw->next = keypasswds;
                   1018:                keypasswds = hpw;
                   1019:            }
                   1020:        }
                   1021:        if (status != -5)
                   1022:            goto done;
                   1023:        fprintf(pgpout, LANG("\n\007Error:  Bad pass phrase.\n"));
                   1024:     }
                   1025:     while (--guesses);
                   1026:     /* Failed - fall through to done */
                   1027: 
                   1028:   done:
                   1029:     fclose(f);
                   1030:     if (hkey)
                   1031:        *hkey = hidekey;
                   1032:     if (status == -5)
                   1033:        return status;
                   1034:     if (status < 0) {
                   1035:        fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"),
                   1036:                keyfile);
                   1037:        fclose(f);              /* close key file */
                   1038:        return -1;
                   1039:     }
                   1040:     if (hpass)
                   1041:        memcpy(hpass, ideakey, sizeof(ideakey));
                   1042:     burn(ideakey);
1.1.1.6   root     1043: 
1.1.1.7   root     1044:     /* Note that readkeypacket has called set_precision */
1.1.1.6   root     1045: 
1.1.1.7   root     1046:     if (d != NULL) {   /* No effective check of pass phrase if d is NULL */
                   1047:        if (!quietmode) {
                   1048:            if (!hidekey)
                   1049:                fprintf(pgpout,
                   1050: LANG("\nAdvisory warning: This RSA secret key is not protected by a \
                   1051: passphrase.\n"));
                   1052:            else
                   1053:                fprintf(pgpout, LANG("Pass phrase is good.  "));
                   1054:        }
                   1055:        if (testeq(d, 0)) {     /* didn't get secret key components */
                   1056:            fprintf(pgpout,
                   1057:                    LANG("\n\007Key file '%s' is not a secret key file.\n"),
                   1058:                    keyfile);
                   1059:            return -1;
                   1060:        }
                   1061:     }
                   1062:     return 0;                  /* normal return */
1.1.1.6   root     1063: 
1.1.1.7   root     1064: }                              /* getsecretkey */
1.1.1.6   root     1065: 
                   1066: /*
                   1067:  * check if a key has a compromise certificate, file pointer must
                   1068:  * be positioned at or right after the key packet.
                   1069:  */
1.1.1.7   root     1070: int is_compromised(FILE * f)
1.1.1.6   root     1071: {
1.1.1.7   root     1072:     long pos, savepos;
                   1073:     byte class, ctb;
                   1074:     int cert_len;
                   1075:     int status = 0;
                   1076: 
                   1077:     pos = savepos = ftell(f);
                   1078: 
                   1079:     nextkeypacket(f, &ctb);
                   1080:     if (is_key_ctb(ctb)) {
                   1081:        pos = ftell(f);
1.1.1.6   root     1082:        nextkeypacket(f, &ctb);
1.1.1.7   root     1083:     }
                   1084:     if (ctb != CTB_KEYCTRL)
                   1085:        fseek(f, pos, SEEK_SET);
                   1086: 
                   1087:     /* file pointer now positioned where compromise cert. should be */
                   1088:     if (fread(&ctb, 1, 1, f) != 1) {
                   1089:        status = -1;
                   1090:        goto ex;
                   1091:     }
                   1092:     if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
                   1093:        cert_len = (int) getpastlength(ctb, f);
                   1094:        if (cert_len > MAX_SIGCERT_LENGTH) {    /* Huge packet length */
                   1095:            status = -1;
                   1096:            goto ex;
                   1097:        }
                   1098:        /* skip version and mdlen byte */
                   1099:        fseek(f, 2L, SEEK_CUR);
                   1100:        if (fread(&class, 1, 1, f) != 1) {
                   1101:            status = -1;
                   1102:            goto ex;
                   1103:        }
                   1104:        status = (class == KC_SIGNATURE_BYTE);
                   1105:     }
                   1106:   ex:
                   1107:     fseek(f, savepos, SEEK_SET);
                   1108:     return status;
1.1.1.6   root     1109: }
                   1110: 
                   1111: 
1.1.1.7   root     1112: /*      Alfred Hitchcock coined the term "mcguffin" for the generic object 
                   1113:    being sought in his films-- the diamond, the microfilm, etc. 
                   1114:  */
1.1.1.6   root     1115: 
                   1116: 
                   1117: /*
                   1118:  * Calculate and display a hash for the public components of the key.
                   1119:  * The components are converted to their external (big-endian) 
                   1120:  * representation, concatenated, and an MD5 on the bit values 
                   1121:  * (i.e. excluding the length value) calculated and displayed in hex.
                   1122:  *
                   1123:  * The hash, or "fingerprint", of the key is useful mainly for quickly
                   1124:  * and easily verifying over the phone that you have a good copy of 
                   1125:  * someone's public key.  Just read the hash over the phone and have
                   1126:  * them check it against theirs.
                   1127:  */
1.1.1.7   root     1128: void getKeyHash(byte * hash, unitptr n, unitptr e)
1.1.1.6   root     1129: {
1.1.1.7   root     1130:     struct MD5Context mdContext;
                   1131:     byte buffer[MAX_BYTE_PRECISION + 2];
                   1132:     byte mdBuffer[MAX_BYTE_PRECISION * 2];
                   1133:     int i, mdIndex = 0, bufIndex;
                   1134: 
                   1135: /* Convert n and e to external (big-endian) byte order and move to mdBuffer */
                   1136:     i = reg2mpi(buffer, n);
                   1137:     for (bufIndex = 2; bufIndex < i + 2; bufIndex++)   /* +2 skips count */
                   1138:        mdBuffer[mdIndex++] = buffer[bufIndex];
                   1139:     i = reg2mpi(buffer, e);
                   1140:     for (bufIndex = 2; bufIndex < i + 2; bufIndex++)   /* +2 skips count */
                   1141:        mdBuffer[mdIndex++] = buffer[bufIndex];
                   1142: 
                   1143:     /* Now evaluate the MD5 for the two MPI's */
                   1144:     MD5Init(&mdContext);
                   1145:     MD5Update(&mdContext, mdBuffer, mdIndex);
                   1146:     MD5Final(hash, &mdContext);
1.1.1.6   root     1147: 
1.1.1.7   root     1148: }                              /* getKeyHash */
1.1.1.6   root     1149: 
                   1150: 
1.1.1.7   root     1151: void printKeyHash(byteptr hash, boolean indent)
1.1.1.6   root     1152: {
1.1.1.7   root     1153:     int i;
1.1.1.6   root     1154: 
1.1.1.7   root     1155: /*      Display the hash.  The format is:
                   1156:    pub  1024/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   1157:    Key fingerprint =  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx 
                   1158:  */
                   1159:     fprintf(pgpout, "%*s  ", indent ? 27 : 1, LANG("Key fingerprint ="));
                   1160:     for (i = 0; i < 8; i++)
                   1161:        fprintf(pgpout, "%02X ", hash[i]);
                   1162:     putc(' ', pgpout);
                   1163:     for (i = 8; i < 16; i++)
                   1164:        fprintf(pgpout, "%02X ", hash[i]);
                   1165:     putc('\n', pgpout);
1.1.1.6   root     1166: 
1.1.1.7   root     1167: }                              /* printKeyHash */
1.1.1.6   root     1168: 
                   1169: 
1.1.1.7   root     1170: void showKeyHash(unitptr n, unitptr e)
1.1.1.6   root     1171: {
1.1.1.7   root     1172:     byte hash[16];
1.1.1.6   root     1173: 
1.1.1.7   root     1174:     getKeyHash(hash, n, e);    /* compute hash of (n,e) */
1.1.1.6   root     1175: 
1.1.1.7   root     1176:     printKeyHash(hash, TRUE);
                   1177: }                              /* showKeyHash */
1.1.1.6   root     1178: 
                   1179: /*
                   1180:  * Lists all entries in keyring that have mcguffin string in userid.
                   1181:  * mcguffin is a null-terminated C string.
                   1182:  */
1.1.1.7   root     1183: int view_keyring(char *mcguffin, char *ringfile, boolean show_signatures,
                   1184:                 boolean show_hashes)
1.1.1.6   root     1185: {
1.1.1.7   root     1186:     FILE *f;
                   1187:     byte ctb, keyctb = 0;
                   1188:     int status;
                   1189:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   1190:     byte keyID[KEYFRAGSIZE];
                   1191:     byte sigkeyID[KEYFRAGSIZE];
                   1192:     byte userid[256];          /* key certificate userid */
                   1193:     char *siguserid;           /* signator userid */
                   1194:     char dfltring[MAX_PATH];
                   1195:     word32 tstamp;
                   1196:     byte *timestamp = (byte *) & tstamp;       /* key certificate timestamp */
                   1197:     int keycounter = 0;
                   1198:     int firstuser = 0;
                   1199:     int compromised = 0;
                   1200:     boolean shownKeyHash = FALSE;
                   1201:     boolean invalid_key = FALSE;       /* unsupported version or bad data */
                   1202:     boolean match = FALSE;
                   1203:     boolean disabled = FALSE;
                   1204:     FILE *savepgpout;
                   1205: 
                   1206:     /* Default keyring to check signature ID's */
                   1207:     strcpy(dfltring, globalPubringName);
                   1208: 
                   1209:     /* open file f for read, in binary (not text) mode... */
                   1210:     if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
                   1211:        fprintf(pgpout,
                   1212:                LANG("\n\007Can't open key ring file '%s'\n"), ringfile);
                   1213:        return -1;
                   1214:     }
                   1215:     if (show_signatures) {
                   1216:        setkrent(ringfile);
                   1217:        setkrent(dfltring);
                   1218:        init_userhash();
                   1219:     }
                   1220: /*      Here's a good format for display of key or signature certificates:
                   1221:    Type bits/keyID    Date       User ID
                   1222:    pub  1024/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   1223:    sec   512/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   1224:    sig   384/xxxxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   1225:  */
                   1226: 
                   1227:     /* XXX Send this to stdout.  Do we always want to do this?
                   1228:      * Why couldn't we have a PGPOUT and PGPERR, and then we wouldn't
                   1229:      * have this problem?  -warlord
                   1230:      */
                   1231:     savepgpout = pgpout;
                   1232:     pgpout = stdout;
                   1233: 
                   1234:     if (moreflag)
                   1235:        open_more();
                   1236:     if (!quietmode) {
                   1237:        fprintf(pgpout, LANG("\nKey ring: '%s'"), ringfile);
                   1238:        if (mcguffin && strlen(mcguffin) > 0)
                   1239:            fprintf(pgpout,
                   1240:                    LANG(", looking for user ID \"%s\"."),
                   1241:                    LOCAL_CHARSET(mcguffin));
                   1242:     }
                   1243:     fprintf(pgpout, LANG("\nType bits/keyID    Date       User ID\n"));
                   1244:     for (;;) {
                   1245:        status = readkeypacket(f, FALSE, &ctb, timestamp, (char *) userid,
                   1246:                               n, e,
                   1247:                               NULL, NULL, NULL, NULL, sigkeyID, NULL);
                   1248:        /* Note that readkeypacket has called set_precision */
                   1249:        if (status == -1) {
                   1250:            status = 0;
                   1251:            break;              /* eof reached */
                   1252:        }
                   1253:        if (status == -4 || status == -6) {
                   1254:            /* only ctb and userid are valid */
                   1255:            memset(sigkeyID, 0, KEYFRAGSIZE);
                   1256:            tstamp = 0;
                   1257:        } else if (status < 0) {
                   1258:            fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"),
                   1259:                    ringfile);
                   1260:            break;
1.1.1.6   root     1261:        }
1.1.1.7   root     1262:        if (is_key_ctb(ctb)) {
                   1263:            byte keyctrl;
1.1.1.6   root     1264: 
1.1.1.7   root     1265:            firstuser = 1;
                   1266:            keyctb = ctb;
                   1267:            compromised = is_compromised(f);
                   1268:            shownKeyHash = FALSE;
                   1269:            if (status < 0) {
                   1270:                invalid_key = TRUE;
                   1271:                memset(keyID, 0, KEYFRAGSIZE);
                   1272:            } else {
                   1273:                invalid_key = FALSE;
                   1274:                extract_keyID(keyID, n);
                   1275:                if (read_trust(f, &keyctrl) == 0 && (keyctrl & KC_DISABLED))
                   1276:                    disabled = TRUE;
                   1277:                else
                   1278:                    disabled = FALSE;
                   1279:            }
1.1.1.6   root     1280:        }
1.1.1.7   root     1281:        if (ctb != CTB_USERID && !is_ctb_type(ctb, CTB_SKE_TYPE))
                   1282:            continue;
                   1283:        if (ctb == CTB_USERID) {
                   1284:            PascalToC((char *) userid);
                   1285:            match = userid_match((char *) userid, mcguffin, n);
                   1286:        }
                   1287:        if (match) {
                   1288:            if (ctb == CTB_USERID) {
                   1289:                if (firstuser) {
                   1290:                    keycounter++;
                   1291:                    if (is_ctb_type(keyctb, CTB_CERT_PUBKEY_TYPE))
                   1292:                        fprintf(pgpout, "pub");
                   1293:                    else if (is_ctb_type(keyctb, CTB_CERT_SECKEY_TYPE))
                   1294:                        fprintf(pgpout, "sec");
                   1295:                    else
                   1296:                        fprintf(pgpout, "???");
                   1297:                    if (invalid_key)
                   1298:                        fprintf(pgpout, "? ");
                   1299:                    else if (disabled)
                   1300:                        fprintf(pgpout, "@ ");
                   1301:                    else
                   1302:                        fprintf(pgpout, "  ");
                   1303:                    fprintf(pgpout, "%4d/%s %s ",
                   1304:                       countbits(n), keyIDstring(keyID), cdate(&tstamp));
                   1305:                } else {
                   1306:                    fprintf(pgpout, "     %s                 ", blankkeyID);
1.1.1.6   root     1307:                }
1.1.1.7   root     1308:                if (compromised && firstuser) {
                   1309:                    fprintf(pgpout, LANG("*** KEY REVOKED ***\n"));
                   1310:                    fprintf(pgpout, "     %s                 ", blankkeyID);
                   1311:                }
                   1312:                firstuser = 0;
                   1313:                fprintf(pgpout, "%s\n", LOCAL_CHARSET((char *) userid));
                   1314: 
                   1315:                /* Display the hashes for n and e if required */
                   1316:                if (show_hashes && !shownKeyHash) {
                   1317:                    showKeyHash(n, e);
                   1318:                    shownKeyHash = TRUE;
                   1319:                }
                   1320:            } else if (show_signatures &&
                   1321:                       !(firstuser && compromised)) {
                   1322:                /* Must be sig cert */
                   1323:                fprintf(pgpout, "sig%c      ", status < 0 ? '?' : ' ');
                   1324:                showkeyID(sigkeyID);
                   1325:                fprintf(pgpout, "             "); /* Indent signator userid */
                   1326:                if ((siguserid = user_from_keyID(sigkeyID)) == NULL)
                   1327:                    fprintf(pgpout,
                   1328:                            LANG("(Unknown signator, can't be checked)\n"));
                   1329:                else
                   1330:                    fprintf(pgpout, "%s\n", LOCAL_CHARSET(siguserid));
                   1331:            }                   /* printing a sig cert */
                   1332:        }                       /* if it has mcguffin */
                   1333:     }                          /* loop for all packets */
                   1334: 
                   1335:     fclose(f);                 /* close key file */
                   1336:     if (show_signatures)
                   1337:        endkrent();
                   1338:     if (keycounter == 1)
                   1339:        fprintf(pgpout, LANG("1 matching key found.\n"));
                   1340:     else
                   1341:        fprintf(pgpout, LANG("%d matching keys found.\n"), keycounter);
                   1342:     close_more();
                   1343:     pgpout = savepgpout;
1.1.1.6   root     1344: 
1.1.1.7   root     1345:     if (status < 0)
                   1346:        return status;
                   1347:     if (mcguffin != NULL && *mcguffin != '\0') {
                   1348:        /* user specified substring */
                   1349:        if (keycounter == 0)
                   1350:            return 67;          /* user not found */
                   1351:        else if (keycounter > 1)
                   1352:            return 1;           /* more than one match */
                   1353:     }
                   1354:     return 0;                  /* normal return */
                   1355: 
                   1356: }                              /* view_keyring */
                   1357: 
                   1358: /*      Lists all entries in keyring that have mcguffin string in userid.
                   1359:    mcguffin is a null-terminated C string.
                   1360:    If options is CHECK_NEW, only new signatures are checked and are
                   1361:    marked as being checked in the trustbyte (called from addto_keyring).
                   1362:  */
                   1363: int dokeycheck(char *mcguffin, char *ringfile, int options)
                   1364: {
                   1365:     FILE *f, *fixedf = NULL;
                   1366:     byte ctb, keyctb = 0;
                   1367:     long fpsig = 0, fpkey = 0, fixpos = 0, trustpos = -1;
                   1368:     int status, sigstatus;
                   1369:     int keypktlen = 0, sigpktlen = 0;
                   1370:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   1371:     byte keyID[KEYFRAGSIZE];
                   1372:     byte sigkeyID[KEYFRAGSIZE];
                   1373:     byte keyuserid[256];       /* key certificate userid */
                   1374:     byte siguserid[256];       /* sig certificate userid */
                   1375:     char dfltring[MAX_PATH];
                   1376:     char *tempring = NULL;
                   1377:     word32 tstamp;
                   1378:     byte *timestamp = (byte *) & tstamp;       /* key certificate timestamp */
                   1379:     word32 sigtstamp;
                   1380:     byte *sigtimestamp = (byte *) & sigtstamp;
                   1381:     byte sigclass;
                   1382:     int firstuser = 0;
                   1383:     int compromised = 0;
                   1384:     boolean invalid_key = FALSE;       /* unsupported version or bad data */
                   1385:     boolean failed = FALSE;
                   1386:     boolean print_userid = FALSE;
                   1387:     byte sigtrust, newtrust;
                   1388:     FILE *savepgpout;
                   1389: 
                   1390:     /* Default keyring to check signature ID's */
                   1391:     strcpy(dfltring, globalPubringName);
                   1392: 
                   1393:     /* open file f, in binary (not text) mode... */
                   1394:     f = fopen(ringfile, FOPRWBIN);
                   1395:     if (f == NULL) {
                   1396:        fprintf(pgpout,
                   1397:                LANG("\n\007Can't open key ring file '%s'\n"), ringfile);
                   1398:        return -1;
                   1399:     }
                   1400: /*      Here's a good format for display of key or signature certificates:
                   1401:    Type bits/keyID   Date       User ID
                   1402:    pub  1024/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   1403:    sec   512/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   1404:    sig   384/xxxxxx yyyy-mm-dd  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   1405:  */
1.1.1.6   root     1406: 
1.1.1.7   root     1407:     /* XXX Send this to stdout.  Do we always want to do this?
                   1408:      * Why couldn't we have a PGPOUT and PGPERR, and then we wouldn't
                   1409:      * have this problem?  -warlord
                   1410:      */
                   1411:     savepgpout = pgpout;
                   1412:     pgpout = stdout;
                   1413: 
                   1414:     if (options & CHECK_NEW) {
                   1415:        fprintf(pgpout, LANG("\nChecking signatures...\n"));
                   1416:     } else {
                   1417:        if (moreflag)
                   1418:            open_more();
                   1419:        if (!quietmode) {
                   1420:            fprintf(pgpout, LANG("\nKey ring: '%s'"), ringfile);
                   1421:            if (mcguffin && strlen(mcguffin) > 0)
                   1422:                fprintf(pgpout, LANG(", looking for user ID \"%s\"."),
                   1423:                        LOCAL_CHARSET(mcguffin));
1.1.1.6   root     1424:        }
1.1.1.7   root     1425:        fprintf(pgpout, LANG("\nType bits/keyID    Date       User ID\n"));
                   1426:     }
                   1427:     for (;;) {
                   1428:        long fpos = ftell(f);
                   1429:        status = readkeypacket(f, FALSE, &ctb, timestamp, (char *) keyuserid,
                   1430:                               n, e,
                   1431:                               NULL, NULL, NULL, NULL, sigkeyID, NULL);
                   1432:        /* Note that readkeypacket has called set_precision */
                   1433:        if (status == -1)
                   1434:            break;              /* eof reached */
                   1435:        if (status == -4 || status == -6) {
                   1436:            /* only ctb and userid are valid */
                   1437:            memset(sigkeyID, 0, KEYFRAGSIZE);
                   1438:            tstamp = 0;
                   1439:        } else if (status < 0) {
                   1440:            fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"),
                   1441:                    ringfile);
                   1442:            fclose(f);          /* close key file */
                   1443:            return -1;
                   1444:        }
                   1445:        if (is_key_ctb(ctb)) {
                   1446:            firstuser = 1;
                   1447:            keyctb = ctb;
                   1448:            fpkey = fpos;
                   1449:            keypktlen = (int) (ftell(f) - fpkey);
                   1450:            compromised = is_compromised(f);
                   1451:            if (status < 0) {
                   1452:                invalid_key = TRUE;
                   1453:                memset(keyID, 0, KEYFRAGSIZE);
                   1454:            } else {
                   1455:                invalid_key = FALSE;
                   1456:                extract_keyID(keyID, n);
                   1457:            }
                   1458:            if (options & CHECK_NEW)
                   1459:                print_userid = TRUE;
                   1460:        }
                   1461:        if (ctb == CTB_USERID) {
                   1462:            PascalToC((char *) keyuserid);
                   1463:        } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
                   1464:            fpsig = fpos;
                   1465:            sigpktlen = (int) (ftell(f) - fpsig);
                   1466:        } else {
                   1467:            continue;
1.1.1.6   root     1468:        }
                   1469: 
1.1.1.7   root     1470:        trustpos = ftell(f);
                   1471:        status = read_trust(f, &sigtrust);
                   1472:        if (status == -1)
                   1473:            break;              /* EOF */
                   1474:        if (status == -7) {
                   1475:            trustpos = -1;
                   1476:            continue;       /* not a keyring or this was a compromise cert. */
                   1477:        }
                   1478:        if (status < 0) {
                   1479:            fclose(f);
                   1480:            return status;
                   1481:        }
                   1482:        if (options & CHECK_NEW) {
                   1483:            if (!is_ctb_type(ctb, CTB_SKE_TYPE))
                   1484:                continue;
                   1485:            if (sigtrust & KC_SIG_CHECKED)
                   1486:                continue;
                   1487:            /* addto_keyring has called setkrent() */
                   1488:            if (user_from_keyID(sigkeyID) == NULL)
                   1489:                continue;       /* unknown signator */
                   1490:        }
                   1491:        /* If we don't list the signatures, continue */
                   1492:        if (!(options & CHECK_NEW) &&
                   1493:            !userid_match((char *) keyuserid, mcguffin, n))
                   1494:            continue;
                   1495: 
                   1496:        if (ctb == CTB_USERID || print_userid) {
                   1497:            /* CHECK_NEW: only print userid if it has new signature */
                   1498:            print_userid = FALSE;
                   1499:            if (firstuser) {
                   1500:                if (is_ctb_type(keyctb, CTB_CERT_PUBKEY_TYPE))
                   1501:                    fprintf(pgpout, "pub");
                   1502:                else if (is_ctb_type(keyctb, CTB_CERT_SECKEY_TYPE))
                   1503:                    fprintf(pgpout, "sec");
                   1504:                else
                   1505:                    fprintf(pgpout, "???");
                   1506:                if (invalid_key)
                   1507:                    fprintf(pgpout, "? ");
                   1508:                else
                   1509:                    fprintf(pgpout, "  ");
                   1510:                fprintf(pgpout, "%4d/%s %s ",
                   1511:                        countbits(n), keyIDstring(keyID), cdate(&tstamp));
                   1512:            } else {
                   1513:                fprintf(pgpout, "          %s            ",
                   1514:                        blankkeyID);
                   1515:            }
                   1516:            if (compromised && firstuser) {
                   1517:                fprintf(pgpout, LANG("*** KEY REVOKED ***\n"));
                   1518:                fprintf(pgpout, "          %s              ",
                   1519:                        blankkeyID);
                   1520:            }
                   1521:            firstuser = 0;
                   1522:            fprintf(pgpout, "%s\n", LOCAL_CHARSET((char *) keyuserid));
                   1523:        }
                   1524:        /* Ignore comments and anything else */
                   1525:        if (!is_ctb_type(ctb, CTB_SKE_TYPE))
                   1526:            continue;
                   1527: 
                   1528:        /* So now we're checking a signature... */
                   1529:        /* Try checking signature on either this ring or dflt ring */
                   1530: 
                   1531:        CToPascal((char *) keyuserid);
                   1532:        sigstatus = check_key_sig(f, fpkey, keypktlen,
                   1533:                                  (char *) keyuserid, f, fpsig,
                   1534:                                  ringfile, (char *) siguserid,
                   1535:                                  sigtimestamp, &sigclass);
                   1536:        if (sigstatus == -2 && strcmp(ringfile, dfltring) != 0) {
                   1537:            sigstatus = check_key_sig(f, fpkey, keypktlen,
                   1538:                                      (char *) keyuserid, f, fpsig,
                   1539:                                      dfltring, (char *) siguserid,
                   1540:                                      sigtimestamp, &sigclass);
                   1541:        }
                   1542:        /*
                   1543:         * Note: sigstatus has the following values:
                   1544:         *   0 Good signature
                   1545:         *  -1 Generic error
                   1546:         *  -2 Can't find key
                   1547:         *  -3 Key too big
                   1548:         *  -4 Key too small
                   1549:         *  -5 Maybe malformed RSA (RSAREF)
                   1550:         *  -6 Unknown PK algorithm
                   1551:         *  -7 Unknown conventional algorithm
                   1552:         *  -8 Unknown version
                   1553:         *  -9 Malformed RSA packet
                   1554:         * -10 Malformed packet
                   1555:         * -20 BAD SIGNATURE
1.1.1.6   root     1556:         */
1.1.1.7   root     1557:        PascalToC((char *) keyuserid);
                   1558:        fseek(f, fpsig + sigpktlen, SEEK_SET);
                   1559:        if (sigclass == KC_SIGNATURE_BYTE)
                   1560:            fprintf(pgpout, "com");
                   1561:        else
                   1562:            fprintf(pgpout, "sig");
                   1563:        if (sigstatus >= 0)
                   1564:            fputs("!      ", pgpout);   /* Good */
                   1565:        else if (status < 0 || sigstatus == -2 || sigstatus == -3)
                   1566:            fputs("?      ", pgpout);   /* Uncheckable */
                   1567:        else if (sigstatus != -20)
                   1568:            fputs("%      ", pgpout);   /* Malformed */
                   1569:        else
                   1570:            fputs("*      ", pgpout);   /* BAD! */
1.1.1.6   root     1571: 
1.1.1.7   root     1572:        showkeyID(sigkeyID);
                   1573: 
                   1574:        /* If we got a keyID, show it */
                   1575:        if (sigstatus >= 0 || sigstatus == -3 ||
                   1576:            (sigstatus <= -5 && sigstatus >= -9) ||
                   1577:            sigstatus == -20) {
                   1578:            PascalToC((char *) siguserid);
                   1579:            fprintf(pgpout, " %s ", cdate(&sigtstamp));
                   1580:            if (sigclass != KC_SIGNATURE_BYTE)
                   1581:                putc(' ', pgpout);
                   1582:            fputs(LOCAL_CHARSET((char *) siguserid), pgpout);
                   1583:            putc('\n', pgpout);
                   1584:            /* If an error, prepare next line for message */
                   1585:            if (sigstatus < 0)
                   1586:                fprintf(pgpout, "          %s             ",
                   1587:                        blankkeyID);
1.1.1.6   root     1588:        } else {
1.1.1.7   root     1589:            /* Indent error messages past date field */
                   1590:            fprintf(pgpout, "             ");
1.1.1.6   root     1591:        }
                   1592: 
1.1.1.7   root     1593:        /* Compute new trust */
                   1594:        newtrust = sigtrust;
                   1595:        if (sigstatus >= 0) {
                   1596:            newtrust |= KC_SIG_CHECKED;
                   1597:        } else if (sigstatus == -2) {
                   1598:            newtrust |= KC_SIG_CHECKED;
                   1599:            newtrust &= ~KC_SIGTRUST_MASK;
                   1600:        } else {
                   1601:            newtrust &= ~KC_SIGTRUST_MASK & ~KC_SIG_CHECKED;
                   1602:            newtrust |= KC_SIGTRUST_UNTRUSTED;
                   1603:        }
1.1.1.6   root     1604: 
1.1.1.7   root     1605:        /* If it changed, write it out */
                   1606:        if (trustpos > 0 && newtrust != sigtrust)
                   1607:            write_trust_pos(f, newtrust, trustpos);
                   1608:        if (sigstatus >= 0)
                   1609:            continue;           /* Skip error code */
                   1610: 
                   1611:        /* An error: print an appropriate message */
                   1612:        if (sigstatus == -2)
                   1613:            fprintf(pgpout, LANG("(Unknown signator, can't be checked)"));
                   1614:        else if (sigstatus == -3)
                   1615:            fprintf(pgpout, LANG("(Key too long, can't be checked)"));
                   1616:        else if (sigstatus == -5)
                   1617:            fprintf(pgpout, LANG("(Malformed or obsolete signature format)"));
                   1618:        else if (sigstatus == -6)
                   1619:            fprintf(pgpout, LANG("(Unknown public-key algorithm)"));
                   1620:        else if (sigstatus == -7)
                   1621:            fprintf(pgpout, LANG("(Unknown hash algorithm)"));
                   1622:        else if (sigstatus == -8)
                   1623:            fprintf(pgpout, LANG("(Unknown signature packet version)"));
                   1624:        else if (sigstatus == -9)
                   1625:            fprintf(pgpout, LANG("(Malformed signature)"));
                   1626:        else if (sigstatus == -10)
                   1627:            fprintf(pgpout, LANG("(Corrupted signature packet)"));
                   1628:        else if (sigstatus == -20)
                   1629:            fprintf(pgpout, LANG("\007**** BAD SIGNATURE! ****"));
                   1630:        else
                   1631:            fprintf(pgpout, "(Unexpected signature error %d)", sigstatus);
                   1632:        putc('\n', pgpout);
1.1.1.6   root     1633: 
1.1.1.7   root     1634:        /*
                   1635:         * If the signature was not too bad, leave it on the key
                   1636:         * ring.
                   1637:         */
                   1638:        if (sigstatus == -2 || sigstatus == -3)
                   1639:            continue;
                   1640:        /*
                   1641:         * The signature was unacceptable, and
                   1642:         * likely to remain that way, so remove it
                   1643:         * from the keyring.
                   1644:         */
                   1645:        if (!failed) {
                   1646:            /* first bad signature: create scratch file */
                   1647:            tempring = tempfile(TMP_TMPDIR);
                   1648:            fixedf = fopen(tempring, FOPWBIN);
                   1649:            failed = TRUE;
                   1650:        }
                   1651:        if (fixedf != NULL) {
                   1652:            copyfilepos(f, fixedf, fpsig - fixpos, fixpos);
                   1653:            fseek(f, fpsig + sigpktlen, SEEK_SET);
                   1654:            if (nextkeypacket(f, &ctb) < 0 || ctb != CTB_KEYCTRL)
                   1655:                fseek(f, fpsig + sigpktlen, SEEK_SET);
                   1656:            fixpos = ftell(f);
                   1657:        }
                   1658:     }                          /* loop for all packets */
1.1.1.6   root     1659: 
1.1.1.7   root     1660:     close_more();
                   1661:     pgpout = savepgpout;
1.1.1.6   root     1662: 
1.1.1.7   root     1663:     if (status < -1) {
                   1664:        fclose(f);
                   1665:        return status;
                   1666:     }
                   1667:     fputc('\n', pgpout);
1.1.1.6   root     1668: 
1.1.1.7   root     1669:     if (failed && fixedf) {
                   1670:        copyfilepos(f, fixedf, -1L, fixpos);
1.1.1.8 ! root     1671:        fclose(f);
1.1.1.7   root     1672:        if (write_error(fixedf)) {
                   1673:            fclose(fixedf);
                   1674:            return -1;
                   1675:        }
                   1676:        fclose(fixedf);
                   1677:        if (!batchmode)
                   1678:            fprintf(pgpout, LANG("Remove bad signatures (Y/n)? "));
                   1679:        if (batchmode || getyesno('y')) {
                   1680:            savetempbak(tempring, ringfile);
                   1681:            failed = 0;
1.1.1.6   root     1682:        }
1.1.1.8 ! root     1683:     } else {
        !          1684:        fclose(f);
1.1.1.7   root     1685:     }
1.1.1.6   root     1686: 
1.1.1.7   root     1687:     return 0;                  /* normal return */
1.1.1.6   root     1688: 
1.1.1.7   root     1689: }                              /* dokeycheck */
1.1.1.6   root     1690: 
                   1691: int backup_rename(char *scratchfile, char *destfile)
                   1692: {
1.1.1.7   root     1693:     /* rename scratchfile to destfile after making a backup file */
                   1694:     char bakfile[MAX_PATH];
1.1.1.6   root     1695: 
1.1.1.7   root     1696:     if (is_tempfile(destfile)) {
                   1697:        remove(destfile);
                   1698:     } else {
                   1699:        if (file_exists(destfile)) {
                   1700:            strcpy(bakfile, destfile);
                   1701:            force_extension(bakfile, BAK_EXTENSION);
                   1702:            remove(bakfile);
                   1703:            rename(destfile, bakfile);
1.1.1.6   root     1704:        }
1.1.1.7   root     1705:     }
                   1706:     return rename2(scratchfile, destfile);
1.1.1.6   root     1707: }
                   1708: 
                   1709: /* Lists all signatures for keys with specified mcguffin string, and asks
                   1710:  * if they should be removed.
                   1711:  */
1.1.1.7   root     1712: int remove_sigs(char *mcguffin, char *ringfile)
1.1.1.6   root     1713: {
1.1.1.7   root     1714:     FILE *f, *g;
                   1715:     byte ctb;
                   1716:     long fp, fpuser;
                   1717:     int packetlength;
                   1718:     int status;
                   1719:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   1720:     byte sigkeyID[KEYFRAGSIZE];
                   1721:     byte userid[256];          /* key certificate userid */
                   1722:     char dfltring[MAX_PATH];
                   1723:     word32 tstamp;
                   1724:     byte *timestamp = (byte *) & tstamp;       /* key certificate timestamp */
                   1725:     int nsigs = 0, nremoved = 0;
                   1726:     int keeping;
                   1727:     char *scratchf;
                   1728: 
                   1729:     /* Default keyring to check signature ID's */
                   1730:     strcpy(dfltring, globalPubringName);
                   1731: 
                   1732:     if (!mcguffin || strlen(mcguffin) == 0)
                   1733:        return -1;
                   1734: 
                   1735:     setoutdir(ringfile);
                   1736:     scratchf = tempfile(0);
                   1737: 
                   1738:     strcpy((char *) userid, mcguffin);
                   1739: 
                   1740:     fprintf(pgpout,
                   1741:            LANG("\nRemoving signatures from userid '%s' in key ring '%s'\n"),
                   1742:            LOCAL_CHARSET(mcguffin), ringfile);
                   1743: 
                   1744:     status = getpublickey(GPK_GIVEUP | GPK_SHOW, ringfile, &fp,
                   1745:                          &packetlength, NULL, timestamp, userid, n, e);
                   1746:     if (status < 0) {
                   1747:        fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"),
                   1748:                ringfile);
                   1749:        return 0;               /* normal return */
                   1750:     }
                   1751:     strcpy((char *) userid, mcguffin);
                   1752:     getpubuserid(ringfile, fp, userid, &fpuser, &packetlength, FALSE);
                   1753:     packetlength += (int) (fpuser - fp);
                   1754: 
                   1755:     /* open file f for read, in binary (not text) mode... */
                   1756:     if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
                   1757:        fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
                   1758:                ringfile);
                   1759:        return -1;
                   1760:     }
                   1761:     /* Count signatures */
                   1762:     fseek(f, fp + packetlength, SEEK_SET);
                   1763:     for (;;) {
                   1764:        status = nextkeypacket(f, &ctb);
                   1765:        if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID)
                   1766:            break;
                   1767:        if (is_ctb_type(ctb, CTB_SKE_TYPE))
                   1768:            ++nsigs;
                   1769:     }
1.1.1.6   root     1770: 
1.1.1.7   root     1771:     rewind(f);
1.1.1.6   root     1772: 
1.1.1.7   root     1773:     if (nsigs == 0) {
                   1774:        fprintf(pgpout, LANG("\nKey has no signatures to remove.\n"));
                   1775:        fclose(f);
                   1776:        return 0;               /* Normal return */
                   1777:     }
                   1778:     fprintf(pgpout, LANG("\nKey has %d signature(s):\n"), nsigs);
1.1.1.6   root     1779: 
1.1.1.7   root     1780:     /* open file g for writing, in binary (not text) mode... */
                   1781:     if ((g = fopen(scratchf, FOPWBIN)) == NULL) {
                   1782:        fclose(f);
                   1783:        return -1;
                   1784:     }
                   1785:     copyfile(f, g, fp + packetlength); /* copy file f to g up through key */
                   1786: 
                   1787:     /* Now print out any following sig certs */
                   1788:     keeping = 1;
                   1789:     for (;;) {
                   1790:        fp = ftell(f);
                   1791:        status = readkeypacket(f, FALSE, &ctb, NULL, NULL, NULL, NULL,
                   1792:                               NULL, NULL, NULL, NULL, sigkeyID, NULL);
                   1793:        packetlength = (int) (ftell(f) - fp);
                   1794:        if ((status < 0 && status != -6 && status != -4) ||
                   1795:            is_key_ctb(ctb) || ctb == CTB_USERID)
                   1796:            break;
                   1797:        if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
                   1798:            fprintf(pgpout, "sig%c     ", status < 0 ? '?' : ' ');
                   1799:            if (status < 0)
                   1800:                memset(sigkeyID, 0, KEYFRAGSIZE);
                   1801:            showkeyID(sigkeyID);
                   1802:            fprintf(pgpout, "               "); /* Indent signator userid */
                   1803:            if (getpublickey(GPK_GIVEUP, ringfile, NULL, NULL,
                   1804:                             sigkeyID, timestamp, userid, n, e) >= 0 ||
                   1805:                getpublickey(GPK_GIVEUP, dfltring, NULL, NULL,
                   1806:                             sigkeyID, timestamp, userid, n, e) >= 0) {
                   1807:                PascalToC((char *) userid);
                   1808:                fprintf(pgpout, "%s\n", LOCAL_CHARSET((char *) userid));
                   1809:            } else {
                   1810:                fprintf(pgpout,
                   1811:                        LANG("(Unknown signator, can't be checked)\n"));
                   1812:            }
                   1813:            fprintf(pgpout, LANG("Remove this signature (y/N)? "));
                   1814:            if (!(keeping = !getyesno('n')))
                   1815:                ++nremoved;
                   1816:        }
                   1817:        if (keeping)
                   1818:            copyfilepos(f, g, (long) packetlength, fp);
                   1819:     }                          /* scanning sig certs */
                   1820:     copyfilepos(f, g, -1L, fp);        /* Copy rest of file */
1.1.1.6   root     1821: 
1.1.1.7   root     1822:     fclose(f);                 /* close key file */
                   1823:     if (write_error(g)) {
                   1824:        fclose(g);
                   1825:        return -1;
                   1826:     }
                   1827:     fclose(g);                 /* close scratch file */
                   1828:     savetempbak(scratchf, ringfile);
                   1829:     if (nremoved == 0)
                   1830:        fprintf(pgpout, LANG("\nNo key signatures removed.\n"));
                   1831:     else
                   1832:        fprintf(pgpout, LANG("\n%d key signature(s) removed.\n"), nremoved);
1.1.1.6   root     1833: 
1.1.1.7   root     1834:     return 0;                  /* normal return */
1.1.1.6   root     1835: 
1.1.1.7   root     1836: }                              /* remove_sigs */
1.1.1.6   root     1837: 
                   1838: /*
                   1839:  * Remove the first entry in key ring that has mcguffin string in userid.
                   1840:  * Or it removes the first matching keyID from the ring.
                   1841:  * A non-NULL keyID takes precedence over a mcguffin specifier.
                   1842:  * mcguffin is a null-terminated C string.
                   1843:  * If secring_too is TRUE, the secret keyring is also checked.
                   1844:  */
1.1.1.7   root     1845: int remove_from_keyring(byte * keyID, char *mcguffin,
                   1846:                        char *ringfile, boolean secring_too)
1.1.1.6   root     1847: {
1.1.1.7   root     1848:     FILE *f;
                   1849:     FILE *g;
                   1850:     long fp, nfp;
                   1851:     int packetlength;
                   1852:     byte ctb;
                   1853:     int status;
                   1854:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   1855:     byte userid[256];          /* key certificate userid */
                   1856:     word32 tstamp;
                   1857:     byte *timestamp = (byte *) & tstamp;       /* key certificate timestamp */
                   1858:     int userids;
                   1859:     boolean rmuserid = FALSE;
                   1860:     char *scratchf;
                   1861:     unsigned secflag = 0;
                   1862: 
                   1863:     default_extension(ringfile, PGP_EXTENSION);
                   1864: 
                   1865:     if ((keyID == NULL) && (!mcguffin || strlen(mcguffin) == 0))
                   1866:        return -1;      /* error, null mcguffin will match everything */
                   1867: 
                   1868:   top:
                   1869:     if (mcguffin)
                   1870:        strcpy((char *) userid, mcguffin);
                   1871: 
                   1872:     fprintf(pgpout, LANG("\nRemoving from key ring: '%s'"), ringfile);
                   1873:     if (mcguffin && strlen(mcguffin) > 0)
                   1874:        fprintf(pgpout, LANG(", userid \"%s\".\n"),
                   1875:                LOCAL_CHARSET(mcguffin));
                   1876: 
                   1877:     status = getpublickey(secflag | GPK_GIVEUP | GPK_SHOW, ringfile, &fp,
                   1878:                          &packetlength, NULL, timestamp, userid, n, e);
                   1879:     if (status < 0 && status != -4 && status != -6) {
                   1880:        fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"),
                   1881:                ringfile);
                   1882:        return 0;               /* normal return */
                   1883:     }
                   1884:     /* Now add to packetlength the subordinate following certificates */
                   1885:     if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
                   1886:        fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
                   1887:                ringfile);
                   1888:        return -1;
                   1889:     }
                   1890:     fseek(f, fp + packetlength, SEEK_SET);
                   1891:     userids = 0;
                   1892:     do {                       /* count user ID's, position nfp at next key */
                   1893:        nfp = ftell(f);
                   1894:        status = nextkeypacket(f, &ctb);
                   1895:        if (status == 0 && ctb == CTB_USERID)
                   1896:            ++userids;
                   1897:     } while (status == 0 && !is_key_ctb(ctb));
                   1898:     if (status < -1) {
                   1899:        fclose(f);
                   1900:        return -1;
                   1901:     }
                   1902:     if (keyID == NULL) {       /* Human confirmation is required. */
                   1903:        /* Supposedly the key was fully displayed by getpublickey */
                   1904:        if (userids > 1) {
                   1905:            fprintf(pgpout, LANG("\nKey has more than one user ID.\n\
1.1.1.6   root     1906: Do you want to remove the whole key (y/N)? "));
1.1.1.7   root     1907:            if (!getyesno('n')) {
                   1908:                /* find out which userid should be removed */
                   1909:                rmuserid = TRUE;
                   1910:                fseek(f, fp + packetlength, SEEK_SET);
                   1911:                for (;;) {
                   1912:                    fp = ftell(f);
                   1913:                    status = readkpacket(f, &ctb, (char *) userid, NULL, NULL);
                   1914:                    if (status < 0 && status != -4 && status != -6
                   1915:                        || is_key_ctb(ctb)) {
                   1916:                        fclose(f);
                   1917:                        fprintf(pgpout, LANG("\nNo more user ID's\n"));
                   1918:                        return -1;
                   1919:                    }
                   1920:                    if (ctb == CTB_USERID) {
                   1921:                        fprintf(pgpout, LANG("Remove \"%s\" (y/N)? "), userid);
                   1922:                        if (getyesno('n'))
                   1923:                            break;
                   1924:                    }
                   1925:                }
                   1926:                do {            /* also remove signatures and trust bytes */
                   1927:                    nfp = ftell(f);
                   1928:                    status = nextkeypacket(f, &ctb);
                   1929:                } while ((status == 0 || status == -4 || status == -6) &&
                   1930:                         !is_key_ctb(ctb) && ctb != CTB_USERID);
                   1931:                if (status < -1 && status != -4 && status != -6) {
                   1932:                    fclose(f);
                   1933:                    return -1;
1.1.1.6   root     1934:                }
1.1.1.7   root     1935:            }
                   1936:        } else if (!force_flag) {       /* only one user ID */
                   1937:            fprintf(pgpout,
                   1938:               LANG("\nAre you sure you want this key removed (y/N)? "));
                   1939:            if (!getyesno('n')) {
1.1.1.6   root     1940:                fclose(f);
1.1.1.7   root     1941:                return -1;      /* user said "no" */
                   1942:            }
1.1.1.6   root     1943:        }
1.1.1.7   root     1944:     }
                   1945:     fclose(f);
                   1946:     packetlength = (int) (nfp - fp);
                   1947: 
                   1948:     /* open file f for read, in binary (not text) mode... */
                   1949:     if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
                   1950:        fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
                   1951:                ringfile);
                   1952:        return -1;
                   1953:     }
                   1954:     setoutdir(ringfile);
                   1955:     scratchf = tempfile(0);
                   1956:     /* open file g for writing, in binary (not text) mode... */
                   1957:     if ((g = fopen(scratchf, FOPWBIN)) == NULL) {
                   1958:        fclose(f);
                   1959:        return -1;
                   1960:     }
                   1961:     copyfilepos(f, g, fp, 0L); /* copy file f to g up to position fp */
                   1962:     copyfilepos(f, g, -1L, fp + packetlength); /* copy rest of file f */
                   1963:     fclose(f);                 /* close key file */
                   1964:     if (write_error(g)) {
                   1965:        fclose(g);
                   1966:        return -1;
                   1967:     }
                   1968:     fclose(g);                 /* close scratch file */
                   1969:     if (secring_too)           /* TRUE if this is the public keyring */
                   1970:        maint_update(scratchf, 0);
                   1971:     savetempbak(scratchf, ringfile);
                   1972:     if (rmuserid)
                   1973:        fprintf(pgpout, LANG("\nUser ID removed from key ring.\n"));
                   1974:     else
                   1975:        fprintf(pgpout, LANG("\nKey removed from key ring.\n"));
                   1976: 
                   1977:     if (secring_too) {
                   1978:        secring_too = FALSE;
                   1979:        strcpy(ringfile, globalSecringName);
                   1980:        strcpy((char *) userid, mcguffin);
                   1981:        if (getpublickey(GPK_GIVEUP | GPK_SECRET, ringfile, NULL,
                   1982:                         NULL, NULL, timestamp, userid, n, e) == 0) {
                   1983:            fprintf(pgpout,
                   1984: LANG("\nKey or user ID is also present in secret keyring.\n\
1.1.1.6   root     1985: Do you also want to remove it from the secret keyring (y/N)? "));
1.1.1.7   root     1986:            if (getyesno('n')) {
                   1987:                secflag = GPK_SECRET;
                   1988:                goto top;
                   1989:            }
1.1.1.6   root     1990:        }
1.1.1.7   root     1991:     }
                   1992:     return 0;                  /* normal return */
1.1.1.6   root     1993: 
1.1.1.7   root     1994: }                              /* remove_from_keyring */
1.1.1.6   root     1995: 
                   1996: /*
                   1997:  * Copy the first entry in key ring that has mcguffin string in
                   1998:  * userid and put it into keyfile.
                   1999:  * mcguffin is a null-terminated C string.
                   2000:  */
1.1.1.7   root     2001: int extract_from_keyring(char *mcguffin, char *keyfile, char *ringfile,
                   2002:                         boolean transflag)
1.1.1.6   root     2003: {
1.1.1.7   root     2004:     FILE *f;
                   2005:     FILE *g;
                   2006:     long fp;
                   2007:     int packetlength = 0;
                   2008:     byte ctb;
                   2009:     byte keyctrl;
                   2010:     int status;
                   2011:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   2012:     byte keyID[KEYFRAGSIZE];
                   2013:     byte userid[256];          /* key certificate userid */
                   2014:     char fname[MAX_PATH], transfile[MAX_PATH], transname[MAX_PATH];
                   2015:     char *tempf = NULL;
                   2016:     word32 tstamp;
                   2017:     byte *timestamp = (byte *) & tstamp;       /* key cert tstamp */
                   2018:     boolean append = FALSE;
                   2019:     boolean whole_ring = FALSE;
                   2020: 
                   2021:     default_extension(ringfile, PGP_EXTENSION);
                   2022: 
                   2023:     if (!mcguffin || strlen(mcguffin) == 0 || strcmp(mcguffin, "*") == 0)
                   2024:        whole_ring = TRUE;
                   2025: 
                   2026:     /* open file f for read, in binary (not text) mode... */
                   2027:     if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
                   2028:        fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
                   2029:                ringfile);
                   2030:        return -1;
                   2031:     }
                   2032:     if (!whole_ring) {
                   2033:        strcpy((char *) userid, mcguffin);
                   2034:        fprintf(pgpout, LANG("\nExtracting from key ring: '%s'"), ringfile);
                   2035:        fprintf(pgpout, LANG(", userid \"%s\".\n"), LOCAL_CHARSET(mcguffin));
                   2036: 
                   2037:        status = getpublickey(GPK_GIVEUP | GPK_SHOW,
                   2038:                              ringfile, &fp, &packetlength, NULL,
                   2039:                              timestamp, userid, n, e);
                   2040:        if (status < 0 && status != -4 && status != -6) {
                   2041:            fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"),
                   2042:                    ringfile);
                   2043:            fclose(f);
                   2044:            return 1;           /* non-normal return */
1.1.1.6   root     2045:        }
1.1.1.7   root     2046:        extract_keyID(keyID, n);
                   2047:     } else {
                   2048:        do                      /* set fp to first key packet */
                   2049:            fp = ftell(f);
                   2050:        while ((status = nextkeypacket(f, &ctb)) >= 0 && !is_key_ctb(ctb));
                   2051:        if (status < 0) {
                   2052:            fclose(f);
                   2053:            return -1;
1.1.1.6   root     2054:        }
1.1.1.7   root     2055:        packetlength = (int) (ftell(f) - fp);
                   2056:     }
1.1.1.6   root     2057: 
1.1.1.7   root     2058:     if (!keyfile || strlen(keyfile) == 0) {
                   2059:        fprintf(pgpout, LANG("\nExtract the above key into which file? "));
                   2060:        if (batchmode)
                   2061:            return -1;
                   2062:        getstring(fname, sizeof(fname) - 4, TRUE);
                   2063:        if (*fname == '\0')
                   2064:            return -1;
                   2065:     } else {
                   2066:        strcpy(fname, keyfile);
                   2067:     }
                   2068:     default_extension(fname, PGP_EXTENSION);
                   2069: 
                   2070:     /* If transport armoring, use a dummy file for keyfile */
                   2071:     if (transflag) {
                   2072:        strcpy(transname, fname);
                   2073:        strcpy(transfile, fname);
                   2074:        force_extension(transfile, ASC_EXTENSION);
                   2075:        tempf = tempfile(TMP_TMPDIR | TMP_WIPE);
                   2076:        strcpy(fname, tempf);
                   2077:     }
                   2078:     if (file_exists(transflag ? transfile : fname)) {
                   2079:        if (!transflag && !whole_ring) {
                   2080:            /* see if the key is already present in fname */
                   2081:            status = getpublickey(GPK_GIVEUP, fname, NULL, NULL, keyID,
                   2082:                                  timestamp, userid, n, e);
                   2083:            if (status >= 0 || status == -4 || status == -6) {
                   2084:                fclose(f);
                   2085:                fprintf(pgpout,
                   2086:                  LANG("Key ID %s is already included in key ring '%s'.\n"),
                   2087:                        keyIDstring(keyID), fname);
                   2088:                return -1;
                   2089:            }
                   2090:        }
                   2091:        if (whole_ring || transflag || status < -1) {
                   2092:            if (!is_tempfile(fname) && !force_flag)
                   2093:                /* Don't ask this for mailmode or for 
                   2094:                 * a tempfile, since its ok.
                   2095:                 */
                   2096:            {
                   2097: /* if status < -1 then fname is not a keyfile,
                   2098:    ask if it should be overwritten */
                   2099:                fprintf(pgpout,
                   2100:             LANG("\n\007Output file '%s' already exists.  Overwrite (y/N)? "),
                   2101:                        transflag ? transfile : fname);
                   2102:                if (!getyesno('n')) {
                   2103:                    fclose(f);
                   2104:                    return -1;  /* user chose to abort */
1.1.1.6   root     2105:                }
1.1.1.7   root     2106:            }
                   2107:        } else {
                   2108:            append = TRUE;
1.1.1.6   root     2109:        }
1.1.1.7   root     2110:     }
                   2111:     if (append)
                   2112:        g = fopen(fname, FOPRWBIN);
                   2113:     else
                   2114:        g = fopen(fname, FOPWBIN);
                   2115:     if (g == NULL) {
1.1.1.6   root     2116:        if (append)
1.1.1.7   root     2117:            fprintf(pgpout,
                   2118:                    LANG("\n\007Can't open key ring file '%s'\n"), ringfile);
1.1.1.6   root     2119:        else
1.1.1.7   root     2120:            fprintf(pgpout,
                   2121:                    LANG("\n\007Unable to create key file '%s'.\n"), fname);
                   2122:        fclose(f);
                   2123:        return -1;
                   2124:     }
                   2125:     if (append)
                   2126:        fseek(g, 0L, SEEK_END);
                   2127:     do {
                   2128:        /* file f is positioned right after key packet */
                   2129:        if (whole_ring && read_trust(f, &keyctrl) == 0
                   2130:            && (keyctrl & KC_DISABLED)) {
                   2131:            do {                /* skip this key */
                   2132:                fp = ftell(f);
                   2133:                status = nextkeypacket(f, &ctb);
                   2134:                packetlength = (int) (ftell(f) - fp);
                   2135:            }
                   2136:            while (!is_key_ctb(ctb) && status >= 0);
                   2137:            continue;
                   2138:        }
                   2139:        if (copyfilepos(f, g, (long) packetlength, fp) < 0) {
                   2140:            /* Copy key out */
                   2141:            status = -2;
                   2142:            break;
1.1.1.6   root     2143:        }
1.1.1.7   root     2144:        /* Copy any following signature or userid packets */
                   2145:        for (;;) {
                   2146:            fp = ftell(f);
                   2147:            status = nextkeypacket(f, &ctb);
                   2148:            packetlength = (int) (ftell(f) - fp);
                   2149:            if (status < 0 || is_key_ctb(ctb))
                   2150:                break;
                   2151:            if (ctb == CTB_USERID || is_ctb_type(ctb, CTB_SKE_TYPE))
1.1.1.6   root     2152:                if (copyfilepos(f, g, (long) packetlength, fp) < 0) {
1.1.1.7   root     2153:                    status = -2;
                   2154:                    break;
1.1.1.6   root     2155:                }
                   2156:        }
1.1.1.7   root     2157:     }
                   2158:     while (whole_ring && status >= 0);
1.1.1.6   root     2159: 
1.1.1.7   root     2160:     fclose(f);
                   2161:     if (status < -1 || write_error(g)) {
1.1.1.6   root     2162:        fclose(g);
1.1.1.7   root     2163:        return -1;
                   2164:     }
                   2165:     fclose(g);
                   2166: 
                   2167:     if (transflag) {
                   2168:        status = armor_file(fname, transfile, transname, NULL);
                   2169:        rmtemp(tempf);
                   2170:        if (status)
                   2171:            return -1;
                   2172:     }
                   2173:     fprintf(pgpout, LANG("\nKey extracted to file '%s'.\n"),
                   2174:            transflag ? transfile : fname);
1.1.1.6   root     2175: 
1.1.1.7   root     2176:     return 0;                  /* normal return */
                   2177: }                              /* extract_from_keyring */
1.1.1.6   root     2178: 
                   2179: 
                   2180: /*======================================================================*/
                   2181: 
                   2182: /* Copy the key data in keyfile into ringfile, replacing the data that
                   2183:    is in ringfile starting at fp and for length packetlength.
                   2184:    keylen is the number of bytes to copy from keyfile
1.1.1.7   root     2185:  */
                   2186: static int merge_key_to_ringfile(char *keyfile, char *ringfile, long fp,
                   2187:                                 int packetlength, long keylen)
1.1.1.6   root     2188: {
1.1.1.7   root     2189:     FILE *f, *g, *h;
                   2190:     char *tempf;
                   2191:     int rc;
                   2192: 
                   2193:     setoutdir(ringfile);
                   2194:     tempf = tempfile(TMP_WIPE);
                   2195:     /* open file f for reading, binary, as keyring file */
                   2196:     if ((f = fopen(ringfile, FOPRBIN)) == NULL)
                   2197:        return -1;
                   2198:     /* open file g for writing, binary, as scratch keyring file */
                   2199:     if ((g = fopen(tempf, FOPWBIN)) == NULL) {
                   2200:        fclose(f);
                   2201:        return -1;
                   2202:     }
                   2203:     /* open file h for reading, binary, as key file to be inserted */
                   2204:     if ((h = fopen(keyfile, FOPRBIN)) == NULL) {
1.1.1.6   root     2205:        fclose(f);
                   2206:        fclose(g);
1.1.1.7   root     2207:        return -1;
                   2208:     }
                   2209:     /* Copy pre-key keyring data from f to g */
                   2210:     copyfile(f, g, fp);
                   2211:     /* Copy temp key data from h to g */
                   2212:     copyfile(h, g, keylen);
                   2213:     /* Copy post-key keyring data from f to g */
                   2214:     copyfilepos(f, g, -1L, fp + packetlength);
                   2215:     fclose(f);
                   2216:     rc = write_error(g);
                   2217:     fclose(g);
                   2218:     fclose(h);
                   2219: 
                   2220:     if (!rc)
                   2221:        savetempbak(tempf, ringfile);
                   2222: 
                   2223:     return rc ? -1 : 0;
                   2224: }                              /* merge_key_to_ringfile */
                   2225: 
                   2226: static int insert_userid(char *keyfile, byte * userid, long fpos)
                   2227: {
                   2228:     /* insert userid and trust byte at position fpos in file keyfile */
                   2229:     char *tmpf;
                   2230:     FILE *f, *g;
                   2231: 
                   2232:     tmpf = tempfile(TMP_TMPDIR);
                   2233:     if ((f = fopen(keyfile, FOPRBIN)) == NULL)
                   2234:        return -1;
                   2235:     if ((g = fopen(tmpf, FOPWBIN)) == NULL) {
1.1.1.6   root     2236:        fclose(f);
1.1.1.7   root     2237:        return -1;
                   2238:     }
                   2239:     copyfile(f, g, fpos);
                   2240:     putc(CTB_USERID, g);
                   2241:     fwrite(userid, 1, userid[0] + 1, g);
                   2242:     write_trust(g, KC_LEGIT_COMPLETE);
                   2243:     copyfile(f, g, -1L);
                   2244:     fclose(f);
                   2245:     if (write_error(g)) {
1.1.1.6   root     2246:        fclose(g);
1.1.1.7   root     2247:        return -1;
                   2248:     }
                   2249:     fclose(g);
                   2250:     return savetempbak(tmpf, keyfile);
1.1.1.6   root     2251: }
                   2252: 
                   2253: int dokeyedit(char *mcguffin, char *ringfile)
                   2254: /*
                   2255:  * Edit the userid and/or pass phrase for an RSA key pair, and
                   2256:  * put them back into the ring files.
                   2257:  */
                   2258: {
1.1.1.7   root     2259:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION],
                   2260:      p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
                   2261:     char *fname, secring[MAX_PATH];
                   2262:     FILE *f;
                   2263:     byte userid[256];
                   2264:     byte userid1[256];
                   2265:     word32 timestamp;          /* key certificate timestamp */
                   2266:     byte keyID[KEYFRAGSIZE];
                   2267:     boolean hidekey;           /* TRUE iff secret key is encrypted */
                   2268:     boolean changed = FALSE, changeID = FALSE;
                   2269:     byte ctb;
                   2270:     int status;
                   2271:     long fpp, fps, trust_pos, keylen;
                   2272:     int pplength = 0, pslength = 0;
                   2273:     byte ideakey[16];
                   2274:     byte keyctrl;
                   2275:     struct IdeaCfbContext cfb;
                   2276: 
                   2277:     if (!ringfile || strlen(ringfile) == 0 || !mcguffin
                   2278:        || strlen(mcguffin) == 0)
                   2279:        return -1;              /* Need ringfile name, user name */
                   2280: 
                   2281:     force_extension(ringfile, PGP_EXTENSION);
                   2282: 
                   2283:     /*
                   2284:      * Although the name of a secret keyring may change in the future, it
                   2285:      * is a safe bet that anything named "secring.pgp" will be a secret
                   2286:      * key ring for the indefinite future.  
                   2287:      */
                   2288:     if (!strcmp(file_tail(ringfile), "secring.pgp") ||
                   2289:        !strcmp(file_tail(ringfile), file_tail(globalSecringName))) {
                   2290:        fprintf(pgpout,
                   2291: LANG("\nThis operation may not be performed on a secret keyring.\n\
1.1.1.6   root     2292: Defaulting to public keyring."));
1.1.1.7   root     2293:        strcpy(ringfile, globalPubringName);
                   2294:     }
                   2295:     strcpy((char *) userid, mcguffin);
                   2296:     fprintf(pgpout, LANG("\nEditing userid \"%s\" in key ring: '%s'.\n"),
                   2297:            LOCAL_CHARSET((char *) userid), ringfile);
                   2298: 
                   2299:     if (!file_exists(ringfile)) {
                   2300:        fprintf(pgpout, LANG("\nCan't open public key ring file '%s'\n"),
                   2301:                ringfile);
                   2302:        return -1;
                   2303:     }
                   2304:     status = getpublickey(GPK_GIVEUP | GPK_SHOW, ringfile, &fpp, &pplength,
                   2305:                          NULL, (byte *) & timestamp, userid, n, e);
                   2306:     if (status < 0) {
                   2307:        fprintf(pgpout, LANG("\n\007Key not found in key ring '%s'.\n"),
                   2308:                ringfile);
                   2309:        return -1;
                   2310:     }
                   2311:     /* Now add to pplength any following key control certificate */
                   2312:     if ((f = fopen(ringfile, FOPRWBIN)) == NULL) {
                   2313:        fprintf(pgpout, LANG("\n\007Can't open key ring file '%s'\n"),
                   2314:                ringfile);
                   2315:        return -1;
                   2316:     }
                   2317:     if (fread(&ctb, 1, 1, f) != 1 || !is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) {
                   2318:        fprintf(pgpout, LANG("\n\007File '%s' is not a public keyring.\n"),
                   2319:                ringfile);
                   2320:        fclose(f);
                   2321:        return -1;
                   2322:     }
                   2323:     fseek(f, fpp, SEEK_SET);
                   2324:     if (is_compromised(f)) {
                   2325:        fprintf(pgpout,
                   2326:                LANG("\n\007This key has been revoked by its owner.\n"));
                   2327:        fclose(f);
                   2328:        return -1;
                   2329:     }
                   2330:     trust_pos = fpp + pplength;
                   2331:     fseek(f, trust_pos, SEEK_SET);
                   2332:     if (read_trust(f, &keyctrl) < 0)
                   2333:        trust_pos = -1;         /* keyfile: no trust byte */
                   2334: 
                   2335:     extract_keyID(keyID, n);
                   2336: 
1.1.1.8 ! root     2337: #if 0
        !          2338:     /*
        !          2339:      * Old code: looks in the same directory as the given keyring, but
        !          2340:      * with the secret keyring filename.
1.1.1.7   root     2341:      */
                   2342:     strcpy(secring, ringfile);
                   2343:     strcpy(file_tail(secring), file_tail(globalSecringName));
                   2344:     if (!file_exists(secring) && strcmp(file_tail(secring), "secring.pgp")) {
                   2345:        strcpy(file_tail(secring), "secring.pgp");
                   2346:     }
1.1.1.8 ! root     2347: #else
        !          2348:     /*
        !          2349:      * What it should do: use the secret keyring, always.
        !          2350:      * Now that the path can be set, this is The Right Thing.
        !          2351:      * It used to be impossible to put the secret and public keyring in
        !          2352:      * different directories, so forcing the same directory name was The
        !          2353:      * Right Thing.  It is no longer.
        !          2354:      */
        !          2355:     strcpy(secring, globalSecringName);
        !          2356: #endif
1.1.1.7   root     2357:     if (!file_exists(secring)) {
                   2358:        fprintf(pgpout, LANG("\nCan't open secret key ring file '%s'\n"),
                   2359:                secring);
                   2360:        fclose(f);
                   2361:        return -1;
                   2362:     }
                   2363:     /* Get position of key in secret key file */
                   2364:     (void) getpublickey(GPK_GIVEUP | GPK_SECRET, secring, &fps, &pslength,
                   2365:                        keyID, (byte *) & timestamp, userid1, n, e);
                   2366:     /* This was done to get us fps and pslength */
                   2367:     status = getsecretkey(GPK_GIVEUP, secring, keyID, (byte *) & timestamp,
                   2368:                          ideakey, &hidekey, userid1, n, e, d, p, q, u);
1.1.1.6   root     2369: 
1.1.1.7   root     2370:     if (status < 0) {  /* key not in secret keyring: edit owner trust */
                   2371:        int i;
1.1.1.6   root     2372: 
1.1.1.7   root     2373:        fprintf(pgpout,
                   2374: LANG("\nNo secret key available.  Editing public key trust parameter.\n"));
                   2375:        if (trust_pos < 0) {
                   2376:            fprintf(pgpout,
                   2377:                    LANG("\n\007File '%s' is not a public keyring.\n"),
                   2378:                    ringfile);
                   2379:            fclose(f);
                   2380:            return -1;
                   2381:        }
                   2382:        show_key(f, fpp, SHOW_ALL);
                   2383: 
                   2384:        init_trust_lst();
                   2385:        fprintf(pgpout, LANG("Current trust for this key's owner is: %s\n"),
                   2386:                trust_lst[keyctrl & KC_OWNERTRUST_MASK]);
                   2387: 
                   2388:        PascalToC((char *) userid);     /* convert to C string for display */
                   2389:        i = ask_owntrust((char *) userid, keyctrl);
                   2390:        if (i == (keyctrl & KC_OWNERTRUST_MASK)) {
                   2391:            fclose(f);
                   2392:            return 0;           /* unchanged */
                   2393:        }
                   2394:        if (i < 0 || i > KC_OWNERTRUST_ALWAYS) {
                   2395:            fclose(f);
                   2396:            return -1;
1.1.1.6   root     2397:        }
1.1.1.7   root     2398:        keyctrl = (keyctrl & ~KC_OWNERTRUST_MASK) | i;
1.1.1.6   root     2399: 
                   2400:        fseek(f, trust_pos, SEEK_SET);
1.1.1.7   root     2401:        write_trust(f, keyctrl);
                   2402:        fclose(f);
                   2403:        fprintf(pgpout, LANG("Public key ring updated.\n"));
                   2404:        return 0;
                   2405:     }
                   2406:     if (trust_pos > 0 && (keyctrl & (KC_BUCKSTOP | KC_OWNERTRUST_MASK)) !=
                   2407:        (KC_OWNERTRUST_ULTIMATE | KC_BUCKSTOP)) {
                   2408:        /* key is in secret keyring but buckstop is not set */
                   2409:        fprintf(pgpout,
                   2410: LANG("\nUse this key as an ultimately-trusted introducer (y/N)? "), userid);
                   2411:        if (getyesno('n')) {
                   2412:            fseek(f, trust_pos, SEEK_SET);
                   2413:            keyctrl = KC_OWNERTRUST_ULTIMATE | KC_BUCKSTOP;
                   2414:            write_trust(f, keyctrl);
                   2415:        }
                   2416:     }
                   2417:     /* Show user her ID again to be clear */
                   2418:     PascalToC((char *) userid);
                   2419:     fprintf(pgpout, LANG("\nCurrent user ID: %s"),
                   2420:            LOCAL_CHARSET((char *) userid));
                   2421:     CToPascal((char *) userid);
                   2422: 
                   2423:     fprintf(pgpout, LANG("\nDo you want to add a new user ID (y/N)? "));
                   2424:     if (getyesno('n')) {       /* user said yes */
                   2425:        fprintf(pgpout, LANG("\nEnter the new user ID: "));
                   2426:        getstring((char *) userid, 255, TRUE);  /* echo keyboard input */
                   2427:        if (userid[0] == '\0') {
                   2428:            fclose(f);
                   2429:            return -1;
                   2430:        }
                   2431:        CONVERT_TO_CANONICAL_CHARSET((char *) userid);
                   2432:        fprintf(pgpout,
                   2433: LANG("\nMake this user ID the primary user ID for this key (y/N)? "));
                   2434:        if (!getyesno('n')) {
                   2435:            /* position file pointer at selected user id */
                   2436:            int pktlen;
                   2437:            long fpuser;
                   2438: 
                   2439:            strcpy((char *) userid1, mcguffin);
                   2440:            if (getpubuserid(ringfile, fpp, userid1, &fpuser, &pktlen,
                   2441:                             FALSE) < 0) {
1.1.1.6   root     2442:                fclose(f);
                   2443:                return -1;
1.1.1.7   root     2444:            }
                   2445:            fseek(f, fpuser, SEEK_SET);
                   2446:        } else {                /* position file pointer at key packet */
                   2447:            fseek(f, fpp, SEEK_SET);
                   2448:        }
                   2449:        nextkeypacket(f, &ctb); /* skip userid or key packet */
                   2450:        do {                    /* new user id will be inserted before next
                   2451:                                   userid or key packet */
                   2452:            fpp = ftell(f);
                   2453:            if (nextkeypacket(f, &ctb) < 0)
                   2454:                break;
                   2455:        } while (ctb != CTB_USERID && !is_key_ctb(ctb));
                   2456:        CToPascal((char *) userid);     /* convert to length-prefixed string */
                   2457:        changeID = TRUE;
                   2458:        changed = TRUE;
                   2459:     }
                   2460:     fclose(f);
                   2461: 
                   2462:     fprintf(pgpout, LANG("\nDo you want to change your pass phrase (y/N)? "));
                   2463:     if (getyesno('n')) {       /* user said yes */
                   2464:        hidekey = (GetHashedPassPhrase((char *) ideakey, 2) > 0);
                   2465:        changed = TRUE;
                   2466:     }
                   2467:     if (!changed) {
                   2468:        fprintf(pgpout, LANG("(No changes will be made.)\n"));
                   2469:        if (hidekey)
                   2470:            burn(ideakey);
                   2471:        goto done;
                   2472:     }
                   2473:     /* init CFB IDEA key */
                   2474:     if (hidekey) {
                   2475:        ideaCfbInit(&cfb, ideakey);
                   2476:        burn(ideakey);
                   2477:     }
                   2478:     /* First write secret key data to a file */
                   2479:     fname = tempfile(TMP_TMPDIR | TMP_WIPE);
                   2480:     writekeyfile(fname, hidekey ? &cfb : 0, timestamp,
                   2481:                 userid, n, e, d, p, q, u);
                   2482: 
                   2483:     if (hidekey)               /* done with IDEA to protect RSA secret key */
                   2484:        ideaCfbDestroy(&cfb);
                   2485: 
                   2486:     if (changeID) {
                   2487:        keylen = -1;
                   2488:     } else {
                   2489:        /* don't copy userid */
                   2490:        f = fopen(fname, FOPRBIN);
                   2491:        if (f == NULL)
                   2492:            goto err;
                   2493:        nextkeypacket(f, &ctb); /* skip key packet */
                   2494:        keylen = ftell(f);
1.1.1.6   root     2495:        fclose(f);
1.1.1.7   root     2496:     }
                   2497:     if (merge_key_to_ringfile(fname, secring, fps, pslength, keylen) < 0) {
                   2498:        fprintf(pgpout, LANG("\n\007Unable to update secret key ring.\n"));
                   2499:        goto err;
                   2500:     }
                   2501:     fprintf(pgpout, LANG("\nSecret key ring updated...\n"));
                   2502: 
                   2503:     /* Now write public key data to file */
                   2504:     if (changeID) {
                   2505:        if (insert_userid(ringfile, userid, fpp) < 0) {
                   2506:            fprintf(pgpout, LANG("\n\007Unable to update public key ring.\n"));
                   2507:            goto err;
                   2508:        }
                   2509:        fprintf(pgpout, LANG("Public key ring updated.\n"));
                   2510:     } else {
                   2511:        fprintf(pgpout, LANG("(No need to update public key ring)\n"));
                   2512:     }
                   2513: 
                   2514:     rmtemp(fname);
                   2515: 
                   2516:   done:
                   2517:     mp_burn(d);                        /* burn sensitive data on stack */
                   2518:     mp_burn(p);
                   2519:     mp_burn(q);
                   2520:     mp_burn(u);
                   2521:     mp_burn(e);
                   2522:     mp_burn(n);
                   2523: 
                   2524:     return 0;                  /* normal return */
                   2525:   err:
                   2526:     mp_burn(d);                        /* burn sensitive data on stack */
                   2527:     mp_burn(p);
                   2528:     mp_burn(q);
                   2529:     mp_burn(u);
                   2530:     mp_burn(e);
                   2531:     mp_burn(n);
1.1.1.6   root     2532: 
1.1.1.7   root     2533:     rmtemp(fname);
1.1.1.6   root     2534: 
1.1.1.7   root     2535:     return -1;                 /* error return */
1.1.1.6   root     2536: 
1.1.1.7   root     2537: }                              /* dokeyedit */
1.1.1.6   root     2538: 
                   2539: int disable_key(char *keyguffin, char *keyfile)
                   2540: {
1.1.1.7   root     2541:     FILE *f;
                   2542:     byte keyctrl;
                   2543:     byte keyID[KEYFRAGSIZE];
                   2544:     byte userid[256];
                   2545:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   2546:     long fp;
                   2547:     int pktlen;
                   2548: 
                   2549:     strcpy((char *) userid, keyguffin);
                   2550:     if (getpublickey(GPK_SHOW | GPK_DISABLED, keyfile, &fp, &pktlen, NULL,
                   2551:                     NULL, userid, n, e) < 0)
                   2552:        return -1;
                   2553: 
                   2554:     extract_keyID(keyID, n);
                   2555:     if (getsecretkey(GPK_GIVEUP, NULL, keyID, NULL, NULL, NULL,
                   2556:                     userid, n, e, NULL, NULL, NULL, NULL) >= 0) {
                   2557:        /* can only compromise if key also in secring */
                   2558:        PascalToC((char *) userid);
                   2559:        fprintf(pgpout,
                   2560:                LANG("\nDo you want to permanently revoke your public key\n\
1.1.1.6   root     2561: by issuing a secret key compromise certificate\n\
1.1.1.7   root     2562: for \"%s\" (y/N)? "), LOCAL_CHARSET((char *) userid));
                   2563:        if (getyesno('n'))
                   2564:            return compromise(keyID, keyfile);
                   2565:     }
                   2566:     if ((f = fopen(keyfile, FOPRWBIN)) == NULL) {
                   2567:        fprintf(pgpout,
                   2568:                LANG("\n\007Can't open key ring file '%s'\n"), keyfile);
                   2569:        return -1;
                   2570:     }
                   2571:     fseek(f, fp + pktlen, SEEK_SET);
                   2572:     if (read_trust(f, &keyctrl) < 0) {
                   2573:        fprintf(pgpout,
                   2574:                LANG("\n\007File '%s' is not a public keyring.\n"), keyfile);
                   2575:        fprintf(pgpout,
                   2576:                LANG("You can only disable keys on your public keyring.\n"));
                   2577:        fclose(f);
                   2578:        return -1;
                   2579:     }
                   2580:     if (keyctrl & KC_DISABLED) {
                   2581:        fprintf(pgpout, LANG("\nKey is already disabled.\n\
1.1.1.6   root     2582: Do you want to enable this key again (y/N)? "));
1.1.1.7   root     2583:        keyctrl &= ~KC_DISABLED;
                   2584:     } else {
                   2585:        fprintf(pgpout, LANG("\nDisable this key (y/N)? "));
                   2586:        keyctrl |= KC_DISABLED;
                   2587:     }
                   2588:     if (!getyesno('n')) {
1.1.1.6   root     2589:        fclose(f);
1.1.1.7   root     2590:        return -1;
                   2591:     }
                   2592:     write_trust_pos(f, keyctrl, fp + pktlen);
                   2593:     fclose(f);
                   2594:     return 0;
                   2595: }                              /* disable_key */
1.1.1.6   root     2596: 
                   2597: 
                   2598: /*======================================================================*/
                   2599: 
                   2600: /*
                   2601:  * Do an RSA key pair generation, and write them out to the keyring files.
                   2602:  * numstr is a decimal string, the desired bitcount for the modulus n.
                   2603:  * numstr2 is a decimal string, the desired bitcount for the exponent e.
1.1.1.8 ! root     2604:  * username is the desired name for the key.
1.1.1.6   root     2605:  */
1.1.1.8 ! root     2606: int dokeygen(char *numstr, char *numstr2, char *username)
1.1.1.6   root     2607: {
1.1.1.7   root     2608:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   2609:     unit d[MAX_UNIT_PRECISION], p[MAX_UNIT_PRECISION];
                   2610:     unit q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
                   2611:     char *fname;
                   2612:     word16 iv[4];              /* for IDEA CFB mode, to protect
                   2613:                                   RSA secret key */
                   2614:     byte userid[256];
                   2615:     short keybits, ebits;
                   2616:     word32 tstamp;
                   2617:     boolean hidekey;           /* TRUE iff secret key is encrypted */
                   2618:     boolean cryptrandflag;
                   2619:     byte ideakey[16];
                   2620:     struct IdeaCfbContext cfb;
1.1.1.6   root     2621: 
1.1.1.7   root     2622:     if (!numstr || strlen(numstr) == 0) {
                   2623:        fputs(LANG("Pick your RSA key size:\n\
1.1.1.6   root     2624:     1)   512 bits- Low commercial grade, fast but less secure\n\
                   2625:     2)   768 bits- High commercial grade, medium speed, good security\n\
                   2626:     3)  1024 bits- \"Military\" grade, slow, highest security\n\
                   2627: Choose 1, 2, or 3, or enter desired number of bits: "), pgpout);
1.1.1.7   root     2628:        numstr = (char *) userid;       /* use userid buffer as scratchpad */
                   2629:        getstring(numstr, 5, TRUE);     /* echo keyboard */
                   2630:     }
                   2631:     keybits = 0;
                   2632:     while ((*numstr >= '0') && (*numstr <= '9'))
                   2633:        keybits = keybits * 10 + (*numstr++ - '0');
                   2634: 
                   2635:     if (keybits == 0)          /* user entered null response */
                   2636:        return -1;              /* error return */
                   2637: 
                   2638:     /* Standard default key sizes: */
                   2639:     if (keybits == 1)
                   2640:        keybits = 512;          /* Low commercial grade */
                   2641:     if (keybits == 2)
                   2642:        keybits = 768;          /* High commercial grade */
                   2643:     if (keybits == 3)
                   2644:        keybits = 1024;         /* Military grade */
1.1.1.6   root     2645: 
                   2646: #ifndef DEBUG
1.1.1.7   root     2647:     /* minimum RSA keysize: */
                   2648:     if (keybits < 384)
                   2649:        keybits = 384;
1.1.1.8 ! root     2650: 
        !          2651:     /*
        !          2652:      * We want to allow some time after release (like, say, 3 months) for
        !          2653:      * this new version to be widely used before people start flinging 2Kbit
        !          2654:      * keys around, which earlier versions of PGP will break on.
        !          2655:      * Accepting 2048-bit keys was supposed to be a quiet change in 2.6.1,
        !          2656:      * so the next release could generate them, but a) the change was
        !          2657:      * messed up, so PGP 2.6.1 didn't, and b) it was announced, causing
        !          2658:      * great noise and commotion.  PGP has always added code to *accept*
        !          2659:      * new features before (usually, one version before) *generating*
        !          2660:      * the new features.  Remember, it's a communications package, so
        !          2661:      * there are at least two people involved, and *both* must be able
        !          2662:      * to deal with the new feature.
        !          2663:      *
        !          2664:      * Please have patience before exercising your paranoia, or AT LEAST
        !          2665:      * before uploading it to key servers and inflicting it on an unprepared
        !          2666:      * world!  The date is about 3 months after the release.
        !          2667:      *
        !          2668:      * @@@ TODO: stop doing this test in 1995.
        !          2669:      */
        !          2670:     if (get_timestamp(NULL) < 0x2efcb600) { /* Telling would spoil the fun */
        !          2671:        if (keybits > 1024)
        !          2672:            keybits = 1024;
        !          2673:     } else {
        !          2674:        if (keybits > 2048)
        !          2675:            keybits = 2048;
        !          2676:     }
1.1.1.6   root     2677: #else
1.1.1.7   root     2678:     if (keybits > MAX_BIT_PRECISION)
                   2679:        keybits = MAX_BIT_PRECISION;
1.1.1.6   root     2680: #endif
                   2681: 
1.1.1.7   root     2682:     ebits = 0;                 /* number of bits in e */
                   2683:     while ((*numstr2 >= '0') && (*numstr2 <= '9'))
                   2684:        ebits = ebits * 10 + (*numstr2++ - '0');
1.1.1.6   root     2685: 
1.1.1.7   root     2686:     fprintf(pgpout,
                   2687:            LANG("Generating an RSA key with a %d-bit modulus.\n"), keybits);
1.1.1.6   root     2688: 
1.1.1.8 ! root     2689:     if (username == NULL || *username == '\0') {
        !          2690:         /* We need to ask for a username */
        !          2691:         fputs(
1.1.1.7   root     2692: LANG("\nYou need a user ID for your public key.  The desired form for this\n\
1.1.1.6   root     2693: user ID is your name, followed by your E-mail address enclosed in\n\
                   2694: <angle brackets>, if you have an E-mail address.\n\
                   2695: For example:  John Q. Smith <[email protected]>\n\
                   2696: Enter a user ID for your public key: \n"), pgpout);
                   2697: #ifdef VMS
1.1.1.8 ! root     2698:        putch('\n'); /* That last newline was just a return, do a real one */
1.1.1.6   root     2699: #endif
1.1.1.8 ! root     2700:        getstring((char *) userid, 255, TRUE);  /* echo keyboard input */
        !          2701:        if (userid[0] == '\0')  /* user entered null response */
        !          2702:            return -1;          /* error return */
        !          2703: 
        !          2704:     } else {
        !          2705:         /* Copy in passed-in username */
        !          2706:         memcpy(userid, username, 255);
        !          2707:        fprintf(pgpout,
        !          2708:            LANG("Generating RSA key-pair with UserID \"%s\".\n"), userid);
        !          2709:     }
1.1.1.7   root     2710:     CONVERT_TO_CANONICAL_CHARSET((char *) userid);
                   2711:     CToPascal((char *) userid);        /* convert to length-prefixed string */
1.1.1.6   root     2712: 
1.1.1.7   root     2713:     fputs(LANG("\nYou need a pass phrase to protect your RSA secret key.\n\
1.1.1.6   root     2714: Your pass phrase can be any sentence or phrase and may have many\n\
                   2715: words, spaces, punctuation, or any other printable characters.\n"), pgpout);
1.1.1.7   root     2716:     hidekey = (GetHashedPassPhrase(ideakey, 2) > 0);
                   2717:     /* init CFB IDEA key */
                   2718:     if (hidekey) {
                   2719:        ideaCfbInit(&cfb, ideakey);
                   2720:        trueRandAccumLater(64); /* IV for encryption */
                   2721:     }
1.1.1.6   root     2722: /* As rsa_keygen does a major accumulation of random bits, if we need
                   2723:  * any others for a seed file, let's get them at the same time.
                   2724:  */
1.1.1.8 ! root     2725:     cryptrandflag = (cryptRandOpen((struct IdeaCfbContext *)0) < 0);
1.1.1.7   root     2726:     if (cryptrandflag)
                   2727:        trueRandAccumLater(192);
                   2728: 
                   2729:     fputs(LANG("\nNote that key generation is a lengthy process.\n"), pgpout);
                   2730: 
                   2731:     if (rsa_keygen(n, e, d, p, q, u, keybits, ebits) < 0) {
                   2732:        fputs(LANG("\n\007Keygen failed!\n"), pgpout);
                   2733:        return -1;              /* error return */
                   2734:     }
                   2735:     putc('\n', pgpout);
                   2736: 
                   2737:     if (verbose) {
                   2738:        fprintf(pgpout, LANG("Key ID %s\n"), key2IDstring(n));
                   2739: 
                   2740:        mp_display(" modulus n = ", n);
                   2741:        mp_display("exponent e = ", e);
                   2742: 
                   2743:        fputs(LANG("Display secret components (y/N)?"), pgpout);
                   2744:        if (getyesno('n')) {
                   2745:            mp_display("exponent d = ", d);
                   2746:            mp_display("   prime p = ", p);
                   2747:            mp_display("   prime q = ", q);
                   2748:            mp_display(" inverse u = ", u);
                   2749:        }
                   2750:     }
                   2751:     tstamp = get_timestamp(NULL);      /* Timestamp when key was generated */
                   2752: 
                   2753:     fputc('\007', pgpout); /* sound the bell when done with lengthy process */
                   2754:     fflush(pgpout);
                   2755: 
                   2756:     /* First, write out the secret key... */
                   2757:     fname = tempfile(TMP_TMPDIR | TMP_WIPE);
                   2758:     writekeyfile(fname, hidekey ? &cfb : 0, tstamp, userid, n, e, d, p, q, u);
                   2759: 
                   2760:     mp_burn(d);
                   2761:     mp_burn(p);
                   2762:     mp_burn(q);
                   2763:     mp_burn(u);
1.1.1.6   root     2764: 
1.1.1.7   root     2765:     if (hidekey)               /* done with IDEA to protect RSA secret key */
                   2766:        ideaCfbDestroy(&cfb);
1.1.1.6   root     2767: 
1.1.1.7   root     2768:     if (file_exists(globalSecringName)) {
                   2769:        merge_key_to_ringfile(fname, globalSecringName, 0L, 0, -1L);
                   2770:        rmtemp(fname);
                   2771:     } else {
                   2772:        savetemp(fname, globalSecringName);
                   2773:     }
                   2774: 
                   2775:     /* Second, write out the public key... */
                   2776:     fname = tempfile(TMP_TMPDIR | TMP_WIPE);
                   2777:     writekeyfile(fname, NULL, tstamp, userid, n, e, NULL, NULL, NULL, NULL);
                   2778:     if (file_exists(globalPubringName)) {
                   2779:        merge_key_to_ringfile(fname, globalPubringName, 0L, 0, -1L);
                   2780:        rmtemp(fname);
                   2781:     } else {
                   2782:        savetemp(fname, globalPubringName);
                   2783:     }
                   2784: 
                   2785:     mp_burn(e);
                   2786:     mp_burn(n);
                   2787: 
                   2788:     fputs(LANG("\007Key generation completed.\n"), pgpout);
                   2789: 
                   2790:     /*
                   2791:      *    If we need a seed file, create it now.
                   2792:      */
                   2793:     if (cryptrandflag) {
                   2794:        trueRandConsume(192);
1.1.1.8 ! root     2795:        cryptRandInit((struct IdeaCfbContext *)0);
        !          2796:        /* It will get saved by exitPGP */
1.1.1.7   root     2797:     }
                   2798:     return 0;                  /* normal return */
                   2799: }                              /* dokeygen */

unix.superglobalmegacorp.com

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