--- pgp/src/keymgmt.c 2018/04/24 16:38:54 1.1.1.2 +++ pgp/src/keymgmt.c 2018/04/24 16:40:28 1.1.1.4 @@ -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,9 +868,9 @@ int getpubusersig(char *keyfile, long us } /* getpubusersig */ -int getsecretkey(boolean giveup, boolean showkey, char *keyfile, byte *keyID, - byte *timestamp, char *passp, boolean *hkey, - byte *userid, unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, +int getsecretkey(int flags, char *keyfile, byte *keyID, + byte *timestamp, byte *hpass, boolean *hkey, byte *userid, + unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u) /* keyID contains key fragment we expect to find in keyfile. If keyID is NULL, then userid contains search target of @@ -862,22 +879,20 @@ int getsecretkey(boolean giveup, boolean secret key file on failure. showkey controls whether we print out the key information when we find it. keyfile, if non-NULL, is the name of the secret key file; if NULL, we use the - default. passp and hkey, if non-NULL, get returned with a copy - of the pass phrase and hidekey variables. + default. hpass and hkey, if non-NULL, get returned with a copy + of the hashed password buffer and hidekey variable. */ { byte ctb; /* returned by readkeypacket */ 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]; + boolean hidekey; /* TRUE iff secret key is encrypted */ word16 iv[4]; /* initialization vector for encryption */ byte ideakey[16]; - extern char password[]; int guesses = 3; + struct hashedpw *hpw, **hpwp; if (keyfile == NULL) { /* use default pathname */ @@ -885,76 +900,153 @@ 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 */ - /* open file f for read, in binary (not text) mode...*/ if ((f = fopen(keyfile,FOPRBIN)) == NULL) return(-1); /* error return */ - /* First guess is null password, so hidekey is FALSE */ + /* First guess is no password */ + hidekey = FALSE; + fseek(f,file_position,SEEK_SET); /* reposition file to key */ + status = readkeypacket(f,hidekey,&ctb,timestamp,(char *)userid, + n,e,d,p,q,u,NULL,NULL); + if (status != -5) /* Anything except bad password */ + goto done; - do /* until good password */ - { if (hkey != NULL) - *hkey = hidekey; - /* Initialize IDEA key */ - if (hidekey) - { if (passp != NULL) - strcpy (passp, passphrase); /* Save phrase for caller */ + /* If we're not signing a key (when we force asking the user), + * check the prevosuly known passwords. + */ + if (!(flags & GPK_ASKPASS)) { + hidekey = TRUE; + /* Then come existing key passwords */ + hpw = keypasswds; + while (hpw) { fill0(iv,8); + memcpy(ideakey, hpw->hash, sizeof(ideakey)); initcfb_idea(iv,ideakey,TRUE); - } - fseek(f,file_position,SEEK_SET); /* reposition file to key */ - status = readkeypacket(f,hidekey,&ctb,timestamp,(char *)userid, - n,e,d,p,q,u,NULL,NULL); - if (hidekey) - close_idea(); /* Release resources */ - - burn((byteptr)passphrase); /* burn sensitive data on stack */ - - if (status == -5) /* bad pass phrase status */ - { if (guesses!=3) /* not first guess of null password? */ - fprintf(pgpout,PSTR("\n\007Error: Bad pass phrase.\n")); - if (!hidekey && *password != '\0') - { /* Try environment variable second */ - strncpy (passphrase, password, sizeof(passphrase)-1); - hashpass (passphrase, strlen(passphrase), ideakey); - hidekey = TRUE; - continue; + fseek(f,file_position,SEEK_SET); + status = readkeypacket(f,hidekey,&ctb,timestamp, + (char *)userid,n,e,d,p,q,u,NULL,NULL); + close_idea(); + if (status != -5) + goto done; + hpw = hpw->next; + } + /* Then try "other" passwords" */ + hpwp = &passwds; + hpw = *hpwp; + while (hpw) { + fill0(iv,8); + memcpy(ideakey, hpw->hash, sizeof(ideakey)); + initcfb_idea(iv,ideakey,TRUE); + fseek(f,file_position,SEEK_SET); + status = readkeypacket(f,hidekey,&ctb,timestamp, + (char *)userid,n,e,d,p,q,u,NULL,NULL); + close_idea(); + if (status >= 0) + { /* Success - move to key password list */ + *hpwp = hpw->next; + hpw->next = keypasswds; + keypasswds = hpw; } - 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) - { /* let user know for which key he should type his password */ - PascalToC((char *)userid); - fprintf(pgpout, PSTR("\nKey for user ID \"%s\"\n"), - LOCAL_CHARSET((char *)userid)); - CToPascal((char *)userid); - } - hidekey = (GetHashedPassPhrase(passphrase, (char *) ideakey, 1) > 0); - continue; /* take it from the top */ - } /* more guesses to go */ + if (status != -5) + goto done; + hpwp = &hpw->next; + hpw = *hpwp; } - if (status < 0) - { fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"), - keyfile); - fclose(f); /* close key file */ - return(-1); + } + /* If batchmode, we don't ask the user. */ + 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; + } + /* Finally, prompt the user. */ + fprintf(pgpout,PSTR("\nYou need a pass phrase to unlock your RSA secret key. ")); + if (!(flags & GPK_SHOW)) + { /* let user know for which key he should type his password */ + PascalToC((char *)userid); + fprintf(pgpout, PSTR("\nKey for user ID \"%s\"\n"), + LOCAL_CHARSET((char *)userid)); + CToPascal((char *)userid); + } + do + { hidekey = (GetHashedPassPhrase((char *) ideakey, 1) > 0); + fill0(iv,8); + initcfb_idea(iv,ideakey,TRUE); + fseek(f,file_position,SEEK_SET); + status = readkeypacket(f,hidekey,&ctb,timestamp, + (char *)userid,n,e,d,p,q,u,NULL,NULL); + close_idea(); + if (status >= 0) + { /* Success - remember this key for later use */ + if (flags & GPK_ASKPASS) + { /* This may be a duplicate because we didn't + * search the lists before - check. + */ + hpw = passwds; + while (hpw) + { if (memcmp(hpw->hash, ideakey, + sizeof(ideakey)) == 0) + goto done; + hpw = hpw->next; + } + hpw = keypasswds; + while (hpw) + { if (memcmp(hpw->hash, ideakey, + sizeof(ideakey)) == 0) + goto done; + hpw = hpw->next; + } + } + /* Insert new key into remember lists. */ + hpw = (struct hashedpw *)malloc(sizeof(struct hashedpw)); + if (hpw) + { /* If malloc fails, just don't remember the phrase */ + memcpy(hpw->hash, ideakey, sizeof(hpw->hash)); + hpw->next = keypasswds; + keypasswds = hpw; + } } - } while (status < 0); /* until key reads OK, with good password */ + if (status != -5) + goto done; + fprintf(pgpout, PSTR("\n\007Error: Bad pass phrase.\n")); + } while (--guesses); + /* Failed - fall through to done */ - fclose(f); /* close key file */ +done: + fclose(f); + if (hkey) + *hkey = hidekey; + if (status == -5) + return status; + if (status < 0) + { fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"), + keyfile); + fclose(f); /* close key file */ + return(-1); + } + + if (hpass) + memcpy(hpass, ideakey, sizeof(ideakey)); + burn (ideakey); /* 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 (d != NULL) /* No effective check of pass phrase if d is NULL */ + { + 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); @@ -1049,32 +1141,37 @@ void getKeyHash( byte *hash, unitptr n, /* Now evaluate the MD5 for the two MPI's */ MD5Init( &mdContext ); MD5Update( &mdContext, mdBuffer, mdIndex ); - MD5Final( &mdContext ); - - for( i = 0; i < 16; i++ ) - hash[i] = mdContext.digest[i]; + MD5Final( hash, &mdContext ); } /* 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 +1180,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 +1206,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 +1222,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 +1251,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 +1264,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 +1290,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 +1316,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 +1369,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 +1394,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 +1440,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 +1503,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 +1534,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 +1561,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 +1578,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 +1618,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 +1645,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 +1704,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 +1774,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 +1832,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 +1865,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 +1877,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 +1899,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 +1930,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 +1954,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 +1976,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 +1986,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 +2018,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 +2073,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. @@ -1957,14 +2146,14 @@ int dokeyedit(char *mcguffin, char *ring /* Edit the userid and/or pass phrase for an RSA key pair, and put them back into the ring files. */ -{ unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION], - p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION]; +{ unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], + d[MAX_UNIT_PRECISION], p[MAX_UNIT_PRECISION], + q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION]; char *fname, secring[MAX_PATH]; FILE *f; word16 iv[4]; /* for IDEA CFB mode, to protect RSA secret key */ byte userid[256]; byte userid1[256]; - char passphrase[256]; word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ byte keyID[KEYFRAGSIZE]; boolean hidekey; /* TRUE iff secret key is encrypted */ @@ -1981,6 +2170,13 @@ int dokeyedit(char *mcguffin, char *ring force_extension(ringfile,PGP_EXTENSION); + if (!strncmp( ringfile, SECRET_KEYRING_FILENAME, strlen( SECRET_KEYRING_FILENAME ))) + { + fprintf(pgpout, PSTR("\nThis operation may not be performed on a secret keyring.\n\ +Defaulting to public keyring.")); + buildfilename( ringfile, PUBLIC_KEYRING_FILENAME ); + } + strcpy((char *)userid, mcguffin); fprintf(pgpout,PSTR("\nEditing userid \"%s\" in key ring: '%s'.\n"), LOCAL_CHARSET((char *)userid),ringfile); @@ -1991,7 +2187,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"), @@ -2005,6 +2201,12 @@ int dokeyedit(char *mcguffin, char *ring return(-1); } + if (fread(&ctb, 1, 1, f) != 1 || !is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) + { fprintf(pgpout,PSTR("\n\007File '%s' is not a public keyring.\n"),ringfile); + fclose(f); + return(-1); + } + fseek(f, fpp, SEEK_SET); if (is_compromised(f)) { fprintf(pgpout, PSTR("\n\007This key has been revoked by its owner.\n")); @@ -2030,11 +2232,11 @@ 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, - passphrase, &hidekey, userid1, n, e, d, p, q, u); + status = getsecretkey(GPK_GIVEUP, secring, keyID, timestamp, + ideakey, &hidekey, userid1, n, e, d, p, q, u); if (status < 0) /* key not in secret keyring: edit owner trust */ { int i; @@ -2110,7 +2312,7 @@ int dokeyedit(char *mcguffin, char *ring } fseek(f, fpuser, SEEK_SET); } - else /* possition file pointer at key packet */ + else /* position file pointer at key packet */ fseek(f, fpp, SEEK_SET); nextkeypacket(f, &ctb); /* skip userid or key packet */ do /* new user id will be inserted before next userid or key packet */ @@ -2126,18 +2328,14 @@ int dokeyedit(char *mcguffin, char *ring fprintf (pgpout,PSTR("\nDo you want to change your pass phrase (y/N)? ")); if (getyesno('n')) /* user said yes */ - { hidekey = (GetHashedPassPhrase(passphrase, (char *) ideakey, 2) > 0); + { hidekey = (GetHashedPassPhrase((char *) ideakey, 2) > 0); changed = TRUE; } - else - { if (hidekey) - hashpass( passphrase, strlen(passphrase), ideakey ); - } if (!changed) { fprintf (pgpout, PSTR("(No changes will be made.)\n")); if (hidekey) - burn((byteptr)passphrase); + burn(ideakey); goto done; } @@ -2145,7 +2343,7 @@ int dokeyedit(char *mcguffin, char *ring if (hidekey) { fill0(iv,8); initcfb_idea(iv,ideakey,FALSE); - burn((byteptr)passphrase); /* burn sensitive data on stack */ + burn(ideakey); } /* First write secret key data to a file */ @@ -2187,22 +2385,22 @@ int dokeyedit(char *mcguffin, char *ring done: mp_burn(d); /* burn sensitive data on stack */ - mp_burn(p); /* " " " " " */ - mp_burn(q); /* " " " " " */ - mp_burn(u); /* " " " " " */ - mp_burn(e); /* " " " " " */ - mp_burn(n); /* " " " " " */ - burn(iv); /* " " " " " */ + mp_burn(p); + mp_burn(q); + mp_burn(u); + mp_burn(e); + mp_burn(n); + burn(iv); return(0); /* normal return */ err: mp_burn(d); /* burn sensitive data on stack */ - mp_burn(p); /* " " " " " */ - mp_burn(q); /* " " " " " */ - mp_burn(u); /* " " " " " */ - mp_burn(e); /* " " " " " */ - mp_burn(n); /* " " " " " */ - burn(iv); /* " " " " " */ + mp_burn(p); + mp_burn(q); + mp_burn(u); + mp_burn(e); + mp_burn(n); + burn(iv); rmtemp(fname); @@ -2211,6 +2409,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 +2487,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) @@ -2255,11 +2514,15 @@ int dokeygen(char *numstr, char *numstr2 #ifndef DEBUG /* minimum RSA keysize: */ - if (keybits<384) keybits=384; - if (keybits>1024) keybits=1024; + if (keybits < 384) keybits=384; + if (keybits > MAX_BIT_PRECISION-UNITSIZE) /* Paranoia */ + keybits = MAX_BIT_PRECISION-UNITSIZE; +#else + if (keybits > MAX_BIT_PRECISION) + keybits = MAX_BIT_PRECISION; #endif -#ifdef notdef +#ifdef notdef /* This annoys everyone, so take it out. */ /* If we use Merritt's modmult algorithm, the primes p and q's bit length should not be an exact multiple of UNITSIZE, because Merritt's modmult algorithm performs slowest in that @@ -2281,25 +2544,30 @@ 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 */ CONVERT_TO_CANONICAL_CHARSET((char *)userid); CToPascal((char *)userid); /* convert to length-prefixed string */ - { char passphrase[256]; - fprintf(pgpout, + { fprintf(pgpout, PSTR("\nYou need a pass phrase to protect your RSA secret key.\n\ Your pass phrase can be any sentence or phrase and may have many\n\ words, spaces, punctuation, or any other printable characters. ")); - hidekey = (GetHashedPassPhrase(passphrase, (char *) ideakey, 2) > 0); + hidekey = (GetHashedPassPhrase((char *) ideakey, 2) > 0); /* init CFB IDEA key */ if (hidekey) { 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 +2629,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 */