--- pgp/src/keymgmt.c 2018/04/24 16:39:37 1.1.1.3 +++ pgp/src/keymgmt.c 2018/04/24 16:40:28 1.1.1.4 @@ -869,8 +869,8 @@ int getpubusersig(char *keyfile, long us 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, + 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 @@ -879,8 +879,8 @@ int getsecretkey(int flags, char *keyfil 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 */ @@ -888,11 +888,11 @@ int getsecretkey(int flags, char *keyfil char keyfilename[MAX_PATH]; /* for getpublickey */ long file_position; 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]; int guesses = 3; + struct hashedpw *hpw, **hpwp; if (keyfile == NULL) { /* use default pathname */ @@ -905,89 +905,140 @@ int getsecretkey(int flags, char *keyfil 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; - } - 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; + 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 (!(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"), - LOCAL_CHARSET((char *)userid)); - CToPascal((char *)userid); + if (status != -5) + goto done; + hpwp = &hpw->next; + hpw = *hpwp; + } + } + /* 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; } - 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); + } + /* 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; } } - if (status < 0 && status != -5) - { fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"), - keyfile); - fclose(f); /* close key file */ - return(-1); - } - } 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 (d != NULL) /* No effective check of pass phrase if d is NULL */ { if (!quietmode) { @@ -1090,10 +1141,7 @@ 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 */ @@ -2098,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 */ @@ -2122,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); @@ -2146,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")); @@ -2175,7 +2236,7 @@ int dokeyedit(char *mcguffin, char *ring timestamp, userid1, n, e); /* This was done to get us fps and pslength */ status = getsecretkey(GPK_GIVEUP, secring, keyID, timestamp, - passphrase, &hidekey, userid1, n, e, d, p, q, u); + ideakey, &hidekey, userid1, n, e, d, p, q, u); if (status < 0) /* key not in secret keyring: edit owner trust */ { int i; @@ -2251,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 */ @@ -2267,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; } @@ -2286,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 */ @@ -2328,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); @@ -2457,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 @@ -2492,17 +2553,15 @@ For example: John Q. Smith <12345.6789@ 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 */ } }