--- pgp/src/keymgmt.c 2018/04/24 16:38:54 1.1.1.2 +++ pgp/src/keymgmt.c 2018/04/24 16:39:37 1.1.1.3 @@ -25,18 +25,20 @@ #endif #include #include +#include "system.h" #include "mpilib.h" #include "idea.h" #include "random.h" #include "crypto.h" #include "fileio.h" #include "keymgmt.h" -#include "genprime.h" #include "rsagen.h" #include "mpiio.h" #include "language.h" #include "pgp.h" #include "md5.h" +#include "charset.h" +#include "keymaint.h" /* @@ -55,7 +57,7 @@ * userid, a substring does not match in this case. * the comparison is always case insensitive */ -boolean userid_match(char *userid, char *substr,unitptr n) +static boolean userid_match(char *userid, char *substr,unitptr n) { boolean match_end = FALSE; int id_len, sub_len, i; @@ -121,38 +123,48 @@ is_key_ctb (byte ctb) } -char *keyIDstring(byte *keyID) -/* Return printable key fragment, which is an abbreviation of - the public key. - Show LEAST significant 64 bits (KEYFRAGSIZE bytes) of modulus, - LSB last. Yes, that's LSB LAST. -*/ -{ short i,j; - static char keyIDbuf[2*KEYFRAGSIZE+1]; - char *bufptr; /* ptr to Key ID string */ +/* +** keyIDstring +** +** Return printable key fragment, which is an abbreviation of the public +** key. Show LEAST significant 64 bits (KEYFRAGSIZE bytes) of modulus, +** LSB last. Yes, that's LSB LAST. +*/ + +char *keyIDstring( byte *keyID ) + { + short i; + char *bufptr; /* ptr to Key ID string */ + static char keyIDbuf[2*KEYFRAGSIZE+1]; + + /* only show bottom 3 bytes of keyID */ + bufptr = keyIDbuf; - fill0(bufptr,sizeof(keyIDbuf)); -#ifdef XLOWFIRST /* LSB-first keyID format */ - j = KEYFRAGSIZE; - for (i=KEYFRAGSIZE-1; i>=0; i--) /* print LSB last */ - { if (--j < 3) /* only show bottom 3 bytes of keyID */ - { sprintf(bufptr,"%02X",keyID[i]); - bufptr += 2; - } - *bufptr = 0; - } -#else /* MSB-first keyID format */ - j = KEYFRAGSIZE; - for (i=0; i= 0; i--) + { + sprintf( bufptr, "%02X", keyID[i] ); + bufptr += 2; + } +#else + /* + ** MSB-first keyID format + */ + + for (i = KEYFRAGSIZE-3; i < KEYFRAGSIZE; i++) + { + sprintf( bufptr, "%02X", keyID[i] ); + bufptr += 2; } - *bufptr = 0; - } #endif - return(keyIDbuf); -} /* keyIDstring */ + *bufptr = '\0'; + return( keyIDbuf ); + } /* keyIDstring */ @@ -195,7 +207,7 @@ char *key2IDstring(unitptr n) -void showkeyID(byteptr keyID) +static void showkeyID(byteptr keyID) /* Print key fragment, which is an abbreviation of the public key. */ { fprintf(pgpout,"%s",keyIDstring(keyID)); @@ -214,7 +226,7 @@ void writekeyID(unitptr n, FILE *f) -boolean checkkeyID(byte *keyID, unitptr n) +static boolean checkkeyID(byte *keyID, unitptr n) /* Compare specified keyID with one derived from actual key modulus n. */ { byte keyID0[KEYFRAGSIZE]; @@ -243,6 +255,7 @@ void write_trust (FILE *f, byte trustbyt fwrite(&trustbyte,1,1,f); /* write key control */ } +static short writekeyfile(char *fname, boolean hidekey, byte *timestamp, byte *userid, unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u) /* Write key components p, q, n, e, d, and u to specified file. @@ -435,7 +448,11 @@ short readkeypacket(FILE *f, boolean hid /* skip packet and return, keeps us in sync when we hit a version error or bad data */ #define SKIP_RETURN(x) \ - {fseek(f,next_packet,SEEK_SET); return(x);} + do \ + { \ + fseek(f,next_packet,SEEK_SET); \ + return(x); \ + } while(0) if (ctb == CTB_USERID) { if (cert_length > 255) @@ -511,7 +528,7 @@ short readkeypacket(FILE *f, boolean hid if (d==NULL) /* skip rest of this key certificate */ SKIP_RETURN(0); /* Normal return */ if (is_secret_key(ctb)) - { byte alg = 0; + { fread (&alg,1,1,f); if (alg && version_error(alg,IDEA_ALGORITHM_BYTE)) SKIP_RETURN(-6); /* Unknown version */ @@ -576,9 +593,9 @@ short readkeypacket(FILE *f, boolean hid -int getpublickey(boolean giveup, boolean showkey, char *keyfile, - long *file_position, int *pktlen, byte *keyID, byte *timestamp, - byte *userid, unitptr n, unitptr e) +int getpublickey(int flags, char *keyfile, long *_file_position, + int *_pktlen, byte *keyID, byte *timestamp, byte *userid, + unitptr n, unitptr e) /* keyID contains key fragment we expect to find in keyfile. If keyID is NULL, then userid contains a C string search target of userid to find in keyfile. @@ -589,7 +606,12 @@ int getpublickey(boolean giveup, boolean that the key was found at. pktlen is the length of the key packet. These values are for the key packet itself, not including any following userid, control, signature, or comment packets. - giveup is TRUE iff we are just going to do a single file search only. + + possible flags: + GPK_GIVEUP: we are just going to do a single file search only. + GPK_SHOW: show the key if found. + GPK_NORVK: skip revoked keys. + GPK_DISABLED: don't ignore disabled keys (when doing userid lookup) Returns -6 if the key was found but the key was not read because of a version error or bad data. The arguments timestamp, n and e are @@ -601,13 +623,17 @@ int getpublickey(boolean giveup, boolean int status, keystatus = -1; boolean keyfound = FALSE; boolean secret = FALSE; - char userid0[256]; /* C string format */ - long fpos, userid_pos; - - userid0[0] = '\0'; + char matchid[256]; /* C string format */ + long fpos; + long file_position = 0; + int pktlen = 0; + boolean skip = FALSE; /* if TRUE: skip until next key packet */ + byte keyctrl; if (keyID==NULL) /* then userid has search target */ - strcpy(userid0,(char *)userid); + strcpy(matchid,(char *)userid); + else + matchid[0] = '\0'; top: if (strlen(keyfile) == 0) /* null filename */ @@ -616,7 +642,7 @@ top: default_extension(keyfile,PGP_EXTENSION); if (!file_exists(keyfile)) - { if (giveup) + { if (flags & GPK_GIVEUP) return(-1); /* give up, error return */ fprintf(pgpout,PSTR("\n\007Keyring file '%s' does not exist. "),keyfile); goto nogood; @@ -633,6 +659,7 @@ top: if ((f = fopen(keyfile,FOPRBIN)) == NULL) return(-1); /* error return */ + keyfound = FALSE; while (TRUE) { fpos = ftell(f); @@ -652,69 +679,69 @@ top: /* Remember packet position and size for last key packet */ if (is_key_ctb(ctb)) - { *file_position = fpos; - *pktlen = (int)(ftell(f) - fpos); + { file_position = fpos; + pktlen = (int)(ftell(f) - fpos); secret = is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE); keystatus = status; + if (!keyID && !(flags & GPK_DISABLED) && !secret + && read_trust(f, &keyctrl) == 0 + && (keyctrl & KC_DISABLED)) + skip = TRUE; + else + skip = FALSE; } /* Only check for matches when we find a USERID packet */ - if (ctb == CTB_USERID) + if (!skip && ctb == CTB_USERID) { /* keyID contains key fragment. Check it against n from keyfile. */ if (keyID!=NULL) { if (keystatus == 0) keyfound = checkkeyID(keyID,n); } else - { /* userid0 is already a C string */ + { /* matchid is already a C string */ PascalToC((char *)userid); /* for C string functions */ /* Accept any matching subset */ - keyfound = userid_match((char *)userid,userid0,n); + keyfound = userid_match((char *)userid,matchid,n); CToPascal((char *)userid); } } if (keyfound) - { if (showkey) - { PascalToC((char *)userid); /* for display */ - fprintf(pgpout,PSTR("\nKey for user ID: %s\n"), - LOCAL_CHARSET((char *)userid)); - switch (keystatus) - { case 0: fprintf(pgpout,PSTR("%d-bit key, Key ID %s, created %s\n"), - countbits(n), key2IDstring(n), cdate((word32 *)timestamp) ); - break; - case -4: fprintf(pgpout,PSTR("Bad key format.\n")); break; - case -6: fprintf(pgpout,PSTR("Unrecognized version.\n")); break; - } - CToPascal((char *)userid); /* restore after display */ - userid_pos = fpos; - if (keyID==NULL) - fseek(f, *file_position + *pktlen, SEEK_SET); - while (((status = readkeypacket(f,FALSE,&ctb,NULL,(char *)userid0, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL) == 0) || - status == -4 || status == -6) && !is_key_ctb(ctb)) - { if (ctb == CTB_USERID) - { PascalToC ((char *)userid0); - if (fpos != userid_pos) - fprintf (pgpout,PSTR("Also known as: %s\n"), - userid0); - } - fpos = ftell(f); + { if (flags & GPK_SHOW) + show_key(f, file_position, 0); + fseek(f, file_position, SEEK_SET); + if ((flags&GPK_NORVK) && keystatus == 0 && is_compromised(f)) + { + if (flags&GPK_SHOW) /* already printed user ID */ + fprintf(pgpout, PSTR("\n\007Sorry, this key has been revoked by its owner.\n")); + else + { + PascalToC((char *) userid); + fprintf(pgpout, PSTR("\nKey for user ID \"%s\"\n\ +has been revoked. You cannot use this key.\n"), + LOCAL_CHARSET((char *)userid)); } + keyfound = FALSE; + skip = TRUE; + /* we're positioned at the key packet, skip it */ + nextkeypacket(f, &ctb); } - fseek(f, *file_position, SEEK_SET); - if (keystatus == 0 && is_compromised(f)) - { fclose(f); - return(1); + else + { /* found key, normal return */ + if (_pktlen) + *_pktlen = pktlen; + if (_file_position) + *_file_position = file_position; + fclose(f); + return(keystatus); } - fclose(f); - return(keystatus); } } /* while TRUE */ fclose(f); /* close key file */ - if (giveup) + if (flags & GPK_GIVEUP) return(-1); /* give up, error return */ if (keyID!=NULL) @@ -724,26 +751,15 @@ top: } else { fprintf(pgpout,PSTR("\n\007Key matching userid '%s' not found in file '%s'.\n"), - LOCAL_CHARSET(userid0),keyfile); + LOCAL_CHARSET(matchid),keyfile); } nogood: - if (giveup || filter_mode) + if (filter_mode || batchmode) return(-1); /* give up, error return */ if (secret) - { /* Look in public key file and see if it's there. */ - char keyfilename[MAX_PATH]; /* for getpublickey */ - buildfilename(keyfilename,PUBLIC_KEYRING_FILENAME); - if (getpublickey(TRUE,FALSE,keyfilename,file_position,pktlen, - keyID,timestamp,userid,n,e) >= 0) - { PascalToC((char * )userid); - fprintf(pgpout,PSTR("\nThis message can only be read by:\n")); - fprintf(pgpout,"\"%s\"\n\n",LOCAL_CHARSET((char *)userid)); - CToPascal((char *)userid); - } fprintf(pgpout,PSTR("Enter secret key filename: ")); - } else fprintf(pgpout,PSTR("Enter public key filename: ")); @@ -784,25 +800,26 @@ int getpubuserid(char *keyfile, long key NULL,NULL,NULL,NULL,NULL,NULL); if (status < 0 || is_key_ctb(ctb)) - break; + { fclose(f); /* close key file */ + return(status ? status : -1); /* give up, error return */ + } /* Only check for matches when we find a USERID packet */ if (ctb == CTB_USERID) - { /* userid is already a C string */ + { if (userid[0] == '0' && userid[1] == 'x') + break; /* use first userid if user specified a keyID */ + /* userid is already a C string */ PascalToC((char *)userid0); /* for C string functions */ /* Accept any matching subset if exact_match is FALSE */ if (userid_match((char *)userid0, (char *) userid, - (exact_match ? NULL : n))) - { *userid_position = fpos; - *userid_len = ( int ) ( ftell(f) - fpos ); - fclose(f); - return(0); /* normal return */ - } + (exact_match ? NULL : n))) + break; } } /* while TRUE */ - - fclose(f); /* close key file */ - return(status ? status : -1); /* give up, error return */ + *userid_position = fpos; + *userid_len = ( int ) ( ftell(f) - fpos ); + fclose(f); + return(0); /* normal return */ } /* getpubuserid */ @@ -851,7 +868,7 @@ int getpubusersig(char *keyfile, long us } /* getpubusersig */ -int getsecretkey(boolean giveup, boolean showkey, char *keyfile, byte *keyID, +int getsecretkey(int flags, char *keyfile, byte *keyID, byte *timestamp, char *passp, boolean *hkey, byte *userid, unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u) @@ -870,13 +887,11 @@ int getsecretkey(boolean giveup, boolean FILE *f; char keyfilename[MAX_PATH]; /* for getpublickey */ long file_position; - int pktlen; /* unused, just to satisfy getpublickey */ int status; boolean hidekey = FALSE; /* TRUE iff secret key is encrypted */ char passphrase[256]; word16 iv[4]; /* initialization vector for encryption */ byte ideakey[16]; - extern char password[]; int guesses = 3; if (keyfile == NULL) @@ -885,8 +900,8 @@ int getsecretkey(boolean giveup, boolean keyfile = keyfilename; } - status = getpublickey(giveup, showkey, keyfile, &file_position, &pktlen, - keyID, timestamp, userid, n, e); + status = getpublickey(flags, keyfile, &file_position, NULL, keyID, + timestamp, userid, n, e); if (status < 0) return(status); /* error return */ @@ -925,9 +940,15 @@ int getsecretkey(boolean giveup, boolean hidekey = TRUE; continue; } + if (batchmode) + { /* PGPPASS (or -z) wrong or not set */ + fprintf(pgpout,PSTR("\n\007Error: Bad pass phrase.\n")); + fclose(f); /* close key file */ + return -1; + } if (--guesses) /* not ran out of guesses yet */ { fprintf(pgpout,PSTR("\nYou need a pass phrase to unlock your RSA secret key. ")); - if (!showkey && guesses == 2) + if (!(flags & GPK_SHOW) && guesses == 2) { /* let user know for which key he should type his password */ PascalToC((char *)userid); fprintf(pgpout, PSTR("\nKey for user ID \"%s\"\n"), @@ -935,10 +956,26 @@ int getsecretkey(boolean giveup, boolean CToPascal((char *)userid); } hidekey = (GetHashedPassPhrase(passphrase, (char *) ideakey, 1) > 0); + /* Save off this password for future passes. + * don't worry -- key signing will DTRT and + * not accept this for multiple key siginings + * + * This should PROBABLY be stored, internally, + * as a hashed pass phrase, but thats not how + * its done anyways... sigh. + * + * Derek Atkins 93-02-25 + */ + strncpy(password, passphrase, sizeof(password) - 1); continue; /* take it from the top */ } /* more guesses to go */ + else + { + fclose(f); /* close key file */ + return(-5); + } } - if (status < 0) + if (status < 0 && status != -5) { fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"), keyfile); fclose(f); /* close key file */ @@ -951,10 +988,14 @@ int getsecretkey(boolean giveup, boolean /* Note that readkeypacket has called set_precision */ if (d != NULL) /* No effective check of pass phrase if d is NULL */ - { if (!hidekey) - fprintf(pgpout,PSTR("\nAdvisory warning: This RSA secret key is not protected by a passphrase.\n")); - else - fprintf(pgpout,PSTR("Pass phrase is good. ")); + { + if (!quietmode) + { + if (!hidekey) + fprintf(pgpout,PSTR("\nAdvisory warning: This RSA secret key is not protected by a passphrase.\n")); + else + fprintf(pgpout,PSTR("Pass phrase is good. ")); + } if (testeq(d,0)) /* didn't get secret key components */ { fprintf(pgpout,PSTR("\n\007Key file '%s' is not a secret key file.\n"),keyfile); @@ -1057,24 +1098,32 @@ void getKeyHash( byte *hash, unitptr n, } /* getKeyHash */ -static void showKeyHash( unitptr n, unitptr e ) +void printKeyHash( byteptr hash, boolean indent ) { - byte hash[16]; int i; - getKeyHash(hash,n,e); /* compute hash of (n,e) */ - /* Display the hash. The format is: pub 1024/xxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Key fingerprint = xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx */ - fprintf( pgpout, "%27s ", PSTR("Key fingerprint =" ) ); + fprintf( pgpout, "%*s ", indent ? 27 : 1, PSTR("Key fingerprint =" ) ); for( i = 0; i < 8; i++ ) fprintf(pgpout, "%02X ", hash[ i ] ); putc( ' ', pgpout); for( i = 8; i < 16; i++ ) fprintf(pgpout, "%02X ", hash[ i ] ); putc( '\n', pgpout); + +} /* printKeyHash */ + + +void showKeyHash( unitptr n, unitptr e ) +{ + byte hash[16]; + + getKeyHash(hash,n,e); /* compute hash of (n,e) */ + + printKeyHash(hash, TRUE); } /* showKeyHash */ @@ -1083,25 +1132,23 @@ int view_keyring(char *mcguffin, char *r mcguffin is a null-terminated C string. */ { FILE *f; - byte ctb, keyctb; - long fpr; - int pktlenr; + byte ctb, keyctb=0; int status; unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; byte keyID[KEYFRAGSIZE]; byte sigkeyID[KEYFRAGSIZE]; byte userid[256]; /* key certificate userid */ - byte siguserid[256]; /* signator userid */ + char *siguserid; /* signator userid */ char dfltring[MAX_PATH]; word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ int keycounter = 0; int firstuser = 0; int compromised = 0; - boolean shownKeyHash; - boolean invalid_key; /* unsupported version or bad data */ + boolean shownKeyHash=FALSE; + boolean invalid_key=FALSE; /* unsupported version or bad data */ boolean match = FALSE; - extern boolean moreflag; + boolean disabled = FALSE; /* Default keyring to check signature ID's */ buildfilename(dfltring,PUBLIC_KEYRING_FILENAME); @@ -1111,6 +1158,12 @@ int view_keyring(char *mcguffin, char *r { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile); return(-1); } + if (show_signatures) + { + setkrent(ringfile); + setkrent(dfltring); + init_userhash(); + } /* Here's a good format for display of key or signature certificates: Type bits/keyID Date User ID @@ -1121,9 +1174,12 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa if (moreflag) open_more(); - fprintf(pgpout,PSTR("\nKey ring: '%s'"),ringfile); - if (mcguffin && strlen(mcguffin) > 0) - fprintf(pgpout,PSTR(", looking for user ID \"%s\"."),LOCAL_CHARSET(mcguffin)); + if (!quietmode) + { + fprintf(pgpout,PSTR("\nKey ring: '%s'"),ringfile); + if (mcguffin && strlen(mcguffin) > 0) + fprintf(pgpout,PSTR(", looking for user ID \"%s\"."),LOCAL_CHARSET(mcguffin)); + } fprintf(pgpout,PSTR("\nType bits/keyID Date User ID\n")); for ( ; ; ) { @@ -1147,6 +1203,8 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa if (is_key_ctb(ctb)) { + byte keyctrl; + firstuser = 1; keyctb = ctb; compromised = is_compromised(f); @@ -1158,6 +1216,10 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa else { invalid_key = FALSE; extract_keyID(keyID, n); + if (read_trust(f, &keyctrl) == 0 && (keyctrl & KC_DISABLED)) + disabled = TRUE; + else + disabled = FALSE; } } @@ -1180,6 +1242,8 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa fprintf(pgpout,"???"); if (invalid_key) fprintf(pgpout,"? "); + else if (disabled) + fprintf(pgpout,"@ "); else fprintf(pgpout," "); fprintf(pgpout,"%4d/%s %s ", @@ -1204,44 +1268,52 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa { fprintf(pgpout,"sig%c ", status < 0 ? '?' : ' '); showkeyID(sigkeyID); fprintf(pgpout," "); /* Indent signator userid */ - if (getpublickey(TRUE, FALSE, ringfile, &fpr, &pktlenr, - sigkeyID, timestamp, siguserid, n, e)>=0 || - getpublickey(TRUE, FALSE, dfltring, &fpr, &pktlenr, - sigkeyID, timestamp, siguserid, n, e)>=0) - { PascalToC((char *)siguserid); - fprintf(pgpout,"%s\n",LOCAL_CHARSET((char *)siguserid)); - } - else + if ((siguserid = user_from_keyID(sigkeyID)) == NULL) fprintf(pgpout,PSTR("(Unknown signator, can't be checked)\n")); + else + fprintf(pgpout,"%s\n",LOCAL_CHARSET(siguserid)); } /* printing a sig cert */ } /* if it has mcguffin */ } /* loop for all packets */ fclose(f); /* close key file */ + if (show_signatures) + endkrent(); fprintf(pgpout,PSTR("%d key(s) examined.\n"),keycounter); close_more(); - return(status); /* normal return */ + if (status < 0) + return status; + if (mcguffin != NULL && *mcguffin != '\0') + { /* user specified substring */ + if (keycounter == 0) + return 67; /* user not found */ + else if (keycounter > 1) + return 1; /* more than one match */ + } + return(0); /* normal return */ } /* view_keyring */ -int dokeycheck(char *mcguffin, char *ringfile, byte *chk_keyID) +int dokeycheck(char *mcguffin, char *ringfile, int options) /* Lists all entries in keyring that have mcguffin string in userid. mcguffin is a null-terminated C string. + If options is CHECK_NEW, only new signatures are checked and are + marked as being checked in the trustbyte (called from addto_keyring). */ -{ FILE *f, *fixedf; - byte ctb, keyctb; - long fpsig, fpkey, fixpos = 0; +{ FILE *f, *fixedf=NULL; + byte ctb, keyctb=0; + long fpsig = 0, fpkey = 0, fixpos = 0, trustpos = -1; int status, sigstatus; - int keypktlen, sigpktlen; + int keypktlen = 0, sigpktlen = 0; unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; byte keyID[KEYFRAGSIZE]; byte sigkeyID[KEYFRAGSIZE]; byte keyuserid[256]; /* key certificate userid */ byte siguserid[256]; /* sig certificate userid */ char dfltring[MAX_PATH]; - char *tempring; + char *tempring = NULL; word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ word32 sigtstamp; @@ -1249,14 +1321,20 @@ int dokeycheck(char *mcguffin, char *rin byte sigclass; int firstuser = 0; int compromised = 0; - boolean invalid_key; /* unsupported version or bad data */ + boolean invalid_key=FALSE; /* unsupported version or bad data */ boolean failed=FALSE; + boolean print_userid=FALSE; + byte sigtrust; /* Default keyring to check signature ID's */ buildfilename(dfltring,PUBLIC_KEYRING_FILENAME); - /* open file f for read, in binary (not text) mode...*/ - if ((f = fopen(ringfile,FOPRBIN)) == NULL) + /* open file f, in binary (not text) mode...*/ + if (options & CHECK_NEW) + f = fopen(ringfile,FOPRWBIN); + else + f = fopen(ringfile,FOPRBIN); + if (f == NULL) { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile); return(-1); } @@ -1268,10 +1346,18 @@ sec 512/xxxxxx yyyy-mm-dd aaaaaaaaaaa sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */ - if (!chk_keyID) - { fprintf(pgpout,PSTR("\nKey ring: '%s'"),ringfile); - if (mcguffin && strlen(mcguffin) > 0) - fprintf(pgpout,PSTR(", looking for user ID \"%s\"."),LOCAL_CHARSET(mcguffin)); + if (options & CHECK_NEW) + { fprintf(pgpout,PSTR("\nChecking signatures...\n")); + } + else + { + if (moreflag) + open_more(); + if (!quietmode) + { fprintf(pgpout,PSTR("\nKey ring: '%s'"),ringfile); + if (mcguffin && strlen(mcguffin) > 0) + fprintf(pgpout,PSTR(", looking for user ID \"%s\"."),LOCAL_CHARSET(mcguffin)); + } fprintf(pgpout,PSTR("\nType bits/keyID Date User ID\n")); } for ( ; ; ) @@ -1306,18 +1392,46 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa { invalid_key = FALSE; extract_keyID(keyID, n); } + if (options & CHECK_NEW) + print_userid = TRUE; } - if (ctb != CTB_USERID && !is_ctb_type(ctb, CTB_SKE_TYPE)) - continue; if (ctb == CTB_USERID) PascalToC((char *)keyuserid); + else if (is_ctb_type(ctb, CTB_SKE_TYPE)) + { fpsig = fpos; + sigpktlen = ( int ) ( ftell(f) - fpsig ); + } else + continue; - if (chk_keyID || userid_match((char *)keyuserid,mcguffin,n)) + if (options & CHECK_NEW) { - if (ctb == CTB_USERID) - { if (chk_keyID) - continue; + if (!is_ctb_type(ctb, CTB_SKE_TYPE)) + continue; + trustpos = ftell(f); + status = read_trust(f, &sigtrust); + if (status == -1) + break; /* EOF */ + if (status == -7) + { trustpos = -1; + continue; /* not a keyring or this was a compromise cert. */ + } + if (status < 0) + { fclose(f); + return status; + } + if (sigtrust & KC_SIG_CHECKED) + continue; + /* addto_keyring has called setkrent() */ + if (user_from_keyID(sigkeyID) == NULL) + continue; /* unknown signator */ + } + + if ((options & CHECK_NEW) || userid_match((char *)keyuserid,mcguffin,n)) + { + if (ctb == CTB_USERID || print_userid) + { /* CHECK_NEW: only print userid if it has new signature */ + print_userid = FALSE; if (firstuser) { if (is_ctb_type(keyctb,CTB_CERT_PUBKEY_TYPE)) fprintf(pgpout,"pub"); @@ -1341,12 +1455,8 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa firstuser = 0; fprintf(pgpout,"%s\n",LOCAL_CHARSET((char *)keyuserid)); } - else /* Must be sig cert */ + if (is_ctb_type(ctb, CTB_SKE_TYPE)) { /* Try checking signature on either this ring or dflt ring */ - if (chk_keyID && memcmp(chk_keyID, sigkeyID, KEYFRAGSIZE)) - continue; /* only check signatures from chk_keyID */ - fpsig = fpos; - sigpktlen = ( int ) ( ftell(f) - fpsig ); CToPascal((char *)keyuserid); sigstatus = check_key_sig (f, fpkey, keypktlen, (char *) keyuserid, f, fpsig, ringfile, (char *) siguserid, sigtimestamp, &sigclass); @@ -1376,7 +1486,11 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa if (sigclass != KC_SIGNATURE_BYTE) fprintf(pgpout, " "); fprintf(pgpout,"%s\n", LOCAL_CHARSET((char *)siguserid)); - if (sigstatus < 0) + if (sigstatus >= 0) + { if (options & CHECK_NEW && trustpos > 0) + write_trust_pos(f, sigtrust|KC_SIG_CHECKED, trustpos); + } + else { fprintf(pgpout," "); fprintf(pgpout,PSTR("\007***** BAD SIGNATURE! *****\n")); if (!failed) @@ -1399,8 +1513,13 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa } /* if it has mcguffin */ } /* loop for all packets */ - if (!chk_keyID) - fputc('\n',pgpout); + close_more(); + if (status < -1) + { + fclose(f); + return status; + } + fputc('\n',pgpout); if (failed) { @@ -1411,8 +1530,9 @@ sig 384/xxxxxx yyyy-mm-dd aaaaaaaaaaa return -1; } fclose(fixedf); - fprintf(pgpout, PSTR("Remove bad signatures (Y/n)? ")); - if (getyesno('y')) + if (!batchmode) + fprintf(pgpout, PSTR("Remove bad signatures (Y/n)? ")); + if (batchmode || getyesno('y')) { savetempbak(tempring, ringfile); failed = 0; @@ -1450,13 +1570,12 @@ int remove_sigs(char *mcguffin, char*rin */ { FILE *f, *g; byte ctb; - long fp, fpr, fpuser; - int packetlength, pktlenr; + long fp, fpuser; + int packetlength; int status; unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; byte sigkeyID[KEYFRAGSIZE]; byte userid[256]; /* key certificate userid */ - byte siguserid[256]; /* signator userid */ char dfltring[MAX_PATH]; word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ @@ -1478,7 +1597,7 @@ int remove_sigs(char *mcguffin, char*rin fprintf(pgpout,PSTR("\nRemoving signatures from userid '%s' in key ring '%s'\n"), LOCAL_CHARSET(mcguffin), ringfile); - status = getpublickey(TRUE, TRUE, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e); + status = getpublickey(GPK_GIVEUP|GPK_SHOW, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e); if (status < 0) { fprintf(pgpout,PSTR("\n\007Key not found in key ring '%s'.\n"),ringfile); return(0); /* normal return */ @@ -1537,10 +1656,10 @@ int remove_sigs(char *mcguffin, char*rin memset(sigkeyID, 0, KEYFRAGSIZE); showkeyID(sigkeyID); fprintf(pgpout," "); /* Indent signator userid */ - if (getpublickey(TRUE, FALSE, ringfile, &fpr, &pktlenr, - sigkeyID, timestamp, userid, n, e)>=0 || - getpublickey(TRUE, FALSE, dfltring, &fpr, &pktlenr, - sigkeyID, timestamp, userid, n, e)>=0) + if (getpublickey(GPK_GIVEUP, ringfile, NULL, NULL, sigkeyID, + timestamp, userid, n, e)>=0 || + getpublickey(GPK_GIVEUP, dfltring, NULL, NULL, sigkeyID, + timestamp, userid, n, e)>=0) { PascalToC((char *)userid); fprintf(pgpout,"%s\n",LOCAL_CHARSET((char *)userid)); } @@ -1607,7 +1726,7 @@ top: fprintf(pgpout,PSTR(", userid \"%s\".\n"), LOCAL_CHARSET(mcguffin)); - status = getpublickey(TRUE, TRUE, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e); + status = getpublickey(GPK_GIVEUP|GPK_SHOW, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e); if (status < 0 && status != -4 && status != -6) { fprintf(pgpout,PSTR("\n\007Key not found in key ring '%s'.\n"),ringfile); return(0); /* normal return */ @@ -1665,7 +1784,7 @@ Do you want to remove the whole key (y/N } } } - else if (!filter_mode) /* only one user ID, interpret -f as force flag */ + else if (!force_flag) /* only one user ID */ { fprintf(pgpout, PSTR("\nAre you sure you want this key removed (y/N)? ")); if (!getyesno('n')) @@ -1698,6 +1817,8 @@ Do you want to remove the whole key (y/N return -1; } fclose(g); /* close scratch file */ + if (secring_too) /* TRUE if this is the public keyring */ + maint_update(scratchf); savetempbak(scratchf,ringfile); if (rmuserid) fprintf(pgpout,PSTR("\nUser ID removed from key ring.\n")); @@ -1708,7 +1829,7 @@ Do you want to remove the whole key (y/N { secring_too = FALSE; buildfilename(ringfile, SECRET_KEYRING_FILENAME); strcpy((char *)userid,mcguffin); - if (getpublickey(TRUE, FALSE, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e) == 0) + if (getpublickey(GPK_GIVEUP, ringfile, NULL, NULL, NULL, timestamp, userid, n, e) == 0) { fprintf(pgpout, PSTR("\nKey or user ID is also present in secret keyring.\n\ Do you also want to remove it from the secret keyring (y/N)? ")); if (getyesno('n')) @@ -1730,15 +1851,16 @@ int extract_from_keyring (char *mcguffin { FILE *f; FILE *g; - long fp, dummy_fp; - int packetlength=0, dummy_packetlength; + long fp; + int packetlength=0; byte ctb; + byte keyctrl; int status; unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; byte keyID[KEYFRAGSIZE]; byte userid[256]; /* key certificate userid */ char fname[MAX_PATH], transfile[MAX_PATH], transname[MAX_PATH]; - char *tempf; + char *tempf = NULL; word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key cert tstamp */ boolean append = FALSE; boolean whole_ring = FALSE; @@ -1760,13 +1882,13 @@ int extract_from_keyring (char *mcguffin fprintf(pgpout,PSTR("\nExtracting from key ring: '%s'"),ringfile); fprintf(pgpout,PSTR(", userid \"%s\".\n"),LOCAL_CHARSET(mcguffin)); - status = getpublickey(TRUE, TRUE, ringfile, &fp, &packetlength, NULL, + status = getpublickey(GPK_GIVEUP|GPK_SHOW, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e); if (status < 0 && status != -4 && status != -6) { fprintf(pgpout,PSTR("\n\007Key not found in key ring '%s'.\n"), ringfile); fclose(f); - return(0); /* normal return */ + return(1); /* non-normal return */ } extract_keyID(keyID, n); } @@ -1784,6 +1906,8 @@ int extract_from_keyring (char *mcguffin if (!keyfile || strlen(keyfile)==0) { fprintf(pgpout, PSTR("\nExtract the above key into which file? ")); + if (batchmode) + return -1; getstring( fname, sizeof(fname)-4, TRUE ); if (*fname == '\0') return(-1); @@ -1804,8 +1928,8 @@ int extract_from_keyring (char *mcguffin { if (!transflag && !whole_ring) { /* see if the key is already present in fname */ - status = getpublickey(TRUE, FALSE, fname, &dummy_fp, &dummy_packetlength, - keyID, timestamp, userid, n, e); + status = getpublickey(GPK_GIVEUP, fname, NULL, NULL, keyID, + timestamp, userid, n, e); if (status >= 0 || status == -4 || status == -6) { fclose(f); fprintf(pgpout,PSTR("Key ID %s is already included in key ring '%s'.\n"), @@ -1814,12 +1938,17 @@ int extract_from_keyring (char *mcguffin } } if (whole_ring || transflag || status < -1) - { /* if status < -1 then fname is not a keyfile, ask if it should be overwritten */ - fprintf(pgpout,PSTR("\n\007Output file '%s' already exists. Overwrite (y/N)? "), - transflag?transfile:fname); - if (!getyesno( 'n' )) - { fclose(f); - return(-1); /* user chose to abort */ + { if (!is_tempfile(fname) && !force_flag) + /* Don't ask this for mailmode or for + * a tempfile, since its ok. + */ + { /* if status < -1 then fname is not a keyfile, ask if it should be overwritten */ + fprintf(pgpout,PSTR("\n\007Output file '%s' already exists. Overwrite (y/N)? "), + transflag?transfile:fname); + if (!getyesno( 'n' )) + { fclose(f); + return(-1); /* user chose to abort */ + } } } else @@ -1841,7 +1970,19 @@ int extract_from_keyring (char *mcguffin if (append) fseek(g, 0L, SEEK_END); do - { + { /* file f is positioned right after key packet */ + if (whole_ring && read_trust(f, &keyctrl) == 0 + && (keyctrl & KC_DISABLED)) + { + do /* skip this key */ + { + fp = ftell(f); + status = nextkeypacket(f, &ctb); + packetlength = ( int ) ( ftell(f) - fp ); + } + while (!is_key_ctb(ctb) && status >= 0); + continue; + } if (copyfilepos(f, g, (long) packetlength, fp) < 0) /* Copy key out */ { status = -2; break; @@ -1884,7 +2025,7 @@ int extract_from_keyring (char *mcguffin /*======================================================================*/ -int merge_key_to_ringfile(char *keyfile, char* ringfile, long fp, +static int merge_key_to_ringfile(char *keyfile, char* ringfile, long fp, int packetlength, long keylen) /* Copy the key data in keyfile into ringfile, replacing the data that is in ringfile starting at fp and for length packetlength. @@ -1991,7 +2132,7 @@ int dokeyedit(char *mcguffin, char *ring return(-1); } - status = getpublickey(TRUE, TRUE, ringfile, &fpp, &pplength, NULL, + status = getpublickey(GPK_GIVEUP|GPK_SHOW, ringfile, &fpp, &pplength, NULL, timestamp, userid, n, e); if (status < 0) { fprintf(pgpout,PSTR("\n\007Key not found in key ring '%s'.\n"), @@ -2030,10 +2171,10 @@ int dokeyedit(char *mcguffin, char *ring } /* Get position of key in secret key file */ - (void)getpublickey(TRUE, FALSE, secring, &fps, &pslength, keyID, + (void)getpublickey(GPK_GIVEUP, secring, &fps, &pslength, keyID, timestamp, userid1, n, e); /* This was done to get us fps and pslength */ - status = getsecretkey(TRUE, FALSE, secring, keyID, timestamp, + status = getsecretkey(GPK_GIVEUP, secring, keyID, timestamp, passphrase, &hidekey, userid1, n, e, d, p, q, u); if (status < 0) /* key not in secret keyring: edit owner trust */ @@ -2211,6 +2352,66 @@ err: } /* dokeyedit */ +int disable_key(char *keyguffin, char *keyfile) +{ + FILE *f; + byte keyctrl; + byte keyID[KEYFRAGSIZE]; + byte userid[256]; + unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; + long fp; + int pktlen; + + strcpy((char *)userid, keyguffin); + if (getpublickey(GPK_SHOW|GPK_DISABLED, keyfile, &fp, &pktlen, NULL, + NULL, userid, n, e) < 0) + return(-1); + + extract_keyID(keyID, n); + if (getsecretkey(GPK_GIVEUP, NULL, keyID, NULL, NULL, NULL, + userid, n, e, NULL, NULL, NULL, NULL) >= 0) + { /* can only compromise if key also in secring */ + PascalToC((char *) userid); + fprintf(pgpout, +PSTR("\nDo you want to permanently revoke your public key\n\ +by issuing a secret key compromise certificate\n\ +for \"%s\" (y/N)? "), LOCAL_CHARSET((char *)userid)); + if (getyesno('n')) + return compromise(keyID, keyfile); + } + if ((f = fopen(keyfile,FOPRWBIN)) == NULL) + { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),keyfile); + return(-1); + } + fseek(f, fp+pktlen, SEEK_SET); + if (read_trust(f, &keyctrl) < 0) + { + fprintf(pgpout,PSTR("\n\007File '%s' is not a public keyring.\n"), keyfile); + fprintf(pgpout, PSTR("You can only disable keys on your public keyring.\n")); + fclose(f); + return -1; + } + if (keyctrl & KC_DISABLED) + { + fprintf(pgpout, PSTR("\nKey is already disabled.\n\ +Do you want to enable this key again (y/N)? ")); + keyctrl &= ~KC_DISABLED; + } + else + { + fprintf(pgpout, PSTR("\nDisable this key (y/N)? ")); + keyctrl |= KC_DISABLED; + } + if (!getyesno('n')) + { fclose(f); + return -1; + } + write_trust_pos(f, keyctrl, fp+pktlen); + fclose(f); + return 0; +} /* disable_key */ + + /*======================================================================*/ @@ -2229,6 +2430,7 @@ int dokeygen(char *numstr, char *numstr2 short keybits,ebits; word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ boolean hidekey; /* TRUE iff secret key is encrypted */ + boolean seedfileexists; /* FALSE if we need to create one */ byte ideakey[16]; if (!numstr || strlen(numstr)==0) @@ -2281,6 +2483,9 @@ user ID is your name, followed by your E , if you have an E-mail address.\n\ For example: John Q. Smith <12345.6789@compuserve.com>\n")); fprintf(pgpout,PSTR("\nEnter a user ID for your public key: \n")); +#ifdef VMS + putch('\n'); /* That last newline was just a return, do a real one */ +#endif getstring((char *)userid,255,TRUE); /* echo keyboard input */ if (userid[0]=='\0') /* user entered null response */ return(-1); /* error return */ @@ -2298,8 +2503,12 @@ words, spaces, punctuation, or any other { fill0(iv,8); initcfb_idea(iv,ideakey,FALSE); burn((byteptr)passphrase); /* burn sensitive data on stack */ + randaccum_later(64); /* IV for encryption */ } } +/* As rsa_keygen does a major accumulation of random bits, if we need + any others for a seed file, let's get them at the same time. */ + seedfileexists = seedfile_exists(); fprintf(pgpout,PSTR("\nNote that key generation is a VERY lengthy process.\n")); @@ -2361,10 +2570,10 @@ words, spaces, punctuation, or any other fprintf(pgpout,PSTR("\007Key generation completed.\n")); - /* Force initialization of cryptographically strong pseudorandom - number generator seed file for later use... + /* If we need a seed file, create it now. */ - strong_pseudorandom((byte *) iv,1); + if (!seedfileexists) + create_seedfile(); return(0); /* normal return */ } /* dokeygen */