Category : C Source Code
Archive   : PGP20SRC.ZIP
Filename : KEYMAINT.C

 
Output of file : KEYMAINT.C contained in archive : PGP20SRC.ZIP
/* keymaint.c - Keyring maintenance pass routines for PGP.
PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.

(c) Copyright 1990-1992 by Philip Zimmermann. All rights reserved.
The author assumes no liability for damages resulting from the use
of this software, even if the damage results from defects in this
software. No warranty is expressed or implied.

All the source code Philip Zimmermann wrote for PGP is available for
free under the "Copyleft" General Public License from the Free
Software Foundation. A copy of that license agreement is included in
the source release package of PGP. Code developed by others for PGP
is also freely available. Other code that has been incorporated into
PGP from other sources was either originally published in the public
domain or was used with permission from the various authors. See the
PGP User's Guide for more complete information about licensing,
patent restrictions on certain algorithms, trademarks, copyrights,
and export controls.

keymaint.c implemented by Branko Lankester.
*/

#include
#include
#include "mpilib.h"
#include "random.h"
#include "crypto.h"
#include "fileio.h"
#include "keymgmt.h"
#include "mpiio.h"
#include "language.h"
#include "pgp.h"


void setup_trust();
int maint_pass1(FILE *f);
int maint_trace_chain(FILE *f);
int maint_cmpfiles(FILE *f, FILE *g);
int trace_sig_chain(FILE *f, byte *fromID, int owner_trust, int depth);
int check_secretkey(FILE *f, long keypos);
int set_legit(FILE *f, long trustpos, int trust_count);
long lookup_by_keyID(FILE *f, byte *srch_keyID);
void show_userid(FILE *f, byte *keyID);
int show_trust(byte, byte);
int show_legit(byte, byte);
void write_trust_pos(FILE *f, byte keyctrl, long pos);

/* returned when trying to do a maintenance pass on a secret keyring or keyfile */
#define ERR_NOTRUST -7

#define TRUST_MASK 7 /* mask for userid/signature trust bytes */
#define SET_TRUST(b,v) (*(b) = (*(b) & ~TRUST_MASK) | (v))
#define TRUST_LEV(b) ((b) & TRUST_MASK)

#define TRUST_FAC(x) (trust_tbl[TRUST_LEV(x)])

/*
* table for tuning user paranoia index.
* values represent contribution of one signature indexed by the
* SIGTRUST of a signature
*/
int trust_tbl[8];

static int marginal_min;
static int complete_min; /* total count needed for a fully legit key */

int marg_min = 2; /* number of marginally trusted signatures needed for
a fully legit key (can be set in config.pgp). */
int compl_min = 1; /* number of fully trusted signatures needed */

char trust_lst[8][16] = {
"undefined", /* PSTR("undefined") */
"unknown", /* PSTR("unknown") */
"untrusted", /* PSTR("untrusted") */
"<3>", /* unused */
"<4>", /* unused */
"marginal", /* PSTR("marginal") */
"complete", /* PSTR("complete") */
"ultimate", /* PSTR("ultimate") */
};

char legit_lst[4][16] = {
"undefined",
"untrusted",
"marginal",
"complete"
};

int trustlst_len = 9; /* length of longest trust word */
int legitlst_len = 9; /* length of longest legit word */

char floppyring[MAX_PATH] = "";
int max_cert_depth = 4; /* maximum nesting of signatures */

static boolean check_only = FALSE;
static boolean mverbose;
static FILE *sec_fp;
static FILE *floppy_fp = NULL;
static int undefined_trust; /* number of legit keys with undef. trust */

int
maintenance(char *ringfile, int options)
{
FILE *f, *g;
int status;
char *tmpring;
char secretkeyring[MAX_PATH];

check_only = (options & MAINT_CHECK) != 0;
mverbose = (options & MAINT_VERBOSE) != 0;
undefined_trust = 0;

if ((tmpring = tempfile(TMP_TMPDIR)) == NULL)
return(-1);
if ((g = fopenbin(tmpring, "w+")) == NULL)
return(-1);

if ((f = fopenbin(ringfile,"r")) == NULL)
{ fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
fclose(g);
return(-1);
}

buildfilename(secretkeyring, SECRET_KEYRING_FILENAME);
if ((sec_fp = fopenbin(secretkeyring, "r")) == NULL)
fprintf(pgpout,PSTR("\nCan't open secret key ring file '%s'\n"),
secretkeyring);

if (!(options & MAINT_SILENT) && *floppyring != '\0' &&
(floppy_fp = fopenbin(floppyring, "r")) == NULL)
fprintf(pgpout,PSTR("\nCan't open backup key ring file '%s'\n"),
floppyring);

if ((status = copyfile(f, g, -1L)) < 0)
{ fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"), ringfile);
goto failed;
}

setup_trust();
if (mverbose)
fprintf(pgpout, PSTR("\nPass 1: Looking for the \"ultimately-trusted\" keys...\n"));
rewind(g);
if ((status = maint_pass1(g)) < 0)
goto failed;

if (mverbose)
fprintf(pgpout, PSTR("\nPass 2: Tracing signature chains...\n"));
rewind(g);
if ((status = maint_trace_chain(g)) < 0)
goto failed;

if (!(options & MAINT_SILENT))
{ if (mverbose)
fprintf(pgpout, PSTR("\nPass 3: Comparing with original keyring...\n"));
rewind(f);
rewind(g);
if ((status = maint_cmpfiles(f, g)) < 0)
goto failed;
} else
status = 1;

fflush(g);
if (ferror(g))
{ status = -1;
goto failed;
}
fclose(f);
fclose(g);
if (sec_fp)
fclose(sec_fp);
if (floppy_fp)
{ fclose(floppy_fp);
floppy_fp = NULL;
}

#ifdef DEBUG
if (check_only)
{
if (undefined_trust)
fprintf(pgpout, "\nKeyring contains %d fully validated key(s) with undefined trust.\n", undefined_trust);
else
if (status == 0)
fprintf(pgpout, "\nMaintenance check OK.\n");
rmtemp(tmpring);
return(0);
}
#endif

if (status > 0) /* keyring is changed */
{
if (options & MAINT_SILENT)
{ /* implicit maintenance pass (after pgp -ka, -kr, -ks) */
remove(ringfile);
if (savetemp(tmpring, ringfile) == NULL)
return(-1);
}
else
{ /* explicit maintenance pass */
fprintf(pgpout, PSTR("Update public keyring '%s' (Y/n)? "), ringfile);
if (!getyesno('y'))
{
rmtemp(tmpring);
return(0);
}
if (savetempbak(tmpring, ringfile))
return(-1);
}
}
else
rmtemp(tmpring);

return(0);

failed:
if (sec_fp)
fclose(sec_fp);
if (floppy_fp)
{ fclose(floppy_fp);
floppy_fp = NULL;
}
fclose(f);
fclose(g);
#ifdef DEBUG
savetempbak(tmpring, "tmpring.pub");
#else
rmtemp(tmpring);
#endif
return(status);
}


/*
* check if axiomatic keys are present in the secret keyring and
* clear userid and signature trust bytes
*/
int
maint_pass1(FILE *f)
{
int status;
char userid[256];
byte keyID[KEYFRAGSIZE];
byte ctb;
byte keyctrl;
boolean buckstop = FALSE, show_user = FALSE;
boolean compromised = FALSE;
int buckstopcount = 0;
int usercount = 0;
long keypos = 0;

while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1)
{
if (status < 0)
return(status);

if (is_ctb_type(ctb, CTB_COMMENT_TYPE))
continue;
if (compromised && is_ctb_type(ctb, CTB_SKE_TYPE) && !usercount)
continue; /* compromise certificate */

/* other packets should have trust byte */
if (read_trust(f, &keyctrl) < 0)
return(ERR_NOTRUST); /* not a public keyring */


if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
{
if (compromised = is_compromised(f))
keyctrl = KC_OWNERTRUST_NEVER;
if ((keyctrl & KC_BUCKSTOP))
{
if (check_secretkey(f, keypos) == 0)
{
++buckstopcount;
buckstop = TRUE;
if (mverbose)
fprintf(pgpout, "* %s",keyIDstring(keyID));
}
else
{ /* not in secret keyring */
keyctrl &= ~KC_BUCKSTOP;
if (TRUST_LEV(keyctrl) == KC_OWNERTRUST_ULTIMATE)
keyctrl = KC_OWNERTRUST_ALWAYS;
if (mverbose)
fprintf(pgpout, ". %s",keyIDstring(keyID));
}
show_user = mverbose;
}
else
{
buckstop = FALSE;
show_user = FALSE;
}
usercount = 0;
keyctrl &= ~KC_VISITED;

}
else if (ctb == CTB_USERID)
{
if (show_user)
{
if (usercount) /* more than one user ID */
fprintf(pgpout, " ");
fprintf(pgpout, " %s\n", EXTERNAL(userid));
}
if (buckstop)
keyctrl = KC_LEGIT_COMPLETE;
else
keyctrl = KC_LEGIT_UNKNOWN;
++usercount;
}
else if (is_ctb_type(ctb, CTB_SKE_TYPE))
{
keyctrl = KC_SIGTRUST_UNDEFINED;
}
fseek(f, -1L, SEEK_CUR);
fwrite(&keyctrl, 1, 1, f);
fseek(f, 0L, SEEK_CUR);
keypos = ftell(f);
}
if (buckstopcount == 0 && mverbose)
{
fprintf(pgpout, PSTR("No ultimately-trusted keys.\n"));
}
return(0);
}


/*
* scan keyring for buckstop keys and start the recursive trace_sig_chain()
* on them
*/
int
maint_trace_chain(FILE *f)
{
int status;
char userid[256];
byte keyID[KEYFRAGSIZE];
long trustpos = 0;
byte ctb;
byte own_trust;
boolean buckstop = FALSE;

while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1)
{
if (status < 0)
return status;

if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
{
trustpos = ftell(f);
if ((status = read_trust(f, &own_trust)) < 0)
return(status);
buckstop = (own_trust & KC_BUCKSTOP) != 0;
userid[0] = '\0';
}
else if (ctb == CTB_USERID)
{
if (buckstop)
{
buckstop = FALSE; /* only for first user id */
if (mverbose)
fprintf(pgpout, "* %s\n", EXTERNAL(userid));

if (TRUST_LEV(own_trust) == KC_OWNERTRUST_UNDEFINED)
{ SET_TRUST(&own_trust, ask_owntrust(userid, own_trust));
write_trust_pos(f, own_trust, trustpos);
}
if (trace_sig_chain(f, keyID, TRUST_LEV(own_trust), 0) < 0)
return(-1);
}
}
}
return(0);
}


/*
* check if the maintenance pass changed anything
* returns 0 if files f and g are equal.
*/
int
maint_cmpfiles(FILE *f, FILE *g)
{
int status;
char userid[256];
byte keyID[KEYFRAGSIZE];
byte sigkeyID[KEYFRAGSIZE];
byte ctb;
byte kc_orig, kc_new;
int usercount = 0;
int changed = 0;

fprintf(pgpout, PSTR(" KeyID Trust Validity User ID\n"));
while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) == 0)
{
if (is_ctb_type(ctb, CTB_COMMENT_TYPE))
continue;
/* other packets should have trust byte */

fseek(g, ftell(f), SEEK_SET);
if (read_trust(f, &kc_orig) < 0 || read_trust(g, &kc_new) < 0)
{ status = ERR_NOTRUST;
break;
}

if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
{
if (is_compromised(f))
{
fprintf(pgpout, "# ");
nextkeypacket(f, &ctb); /* skip compromise certificate */
nextkeypacket(g, &ctb);
}
else if ((kc_new & KC_BUCKSTOP))
fprintf(pgpout, "* ");
else
fprintf(pgpout, " ");

fprintf(pgpout, "%s ",keyIDstring(keyID));
changed += show_trust(kc_new, kc_orig);
usercount = 0;
userid[0] = '\0';
}
else if (ctb == CTB_USERID)
{
if (usercount) /* more than one user ID */
fprintf(pgpout, " %*s", trustlst_len, "");
++usercount;
changed += show_legit(kc_new, kc_orig);
fprintf(pgpout, "%s\n", EXTERNAL(userid));
}
else if (is_ctb_type(ctb, CTB_SKE_TYPE))
{
if (kc_new & KC_CONTIG)
fprintf(pgpout, "c ");
else
fprintf(pgpout, " ");
changed += show_trust(kc_new, kc_orig);
fprintf(pgpout, " %*s", legitlst_len, "");
show_userid(f, sigkeyID);
}
}
if (status >= -1 && changed)
fprintf(pgpout, PSTR("\n%d \"trust byte(s)\" changed.\n"), changed);
if (status < -1) /* -1 is OK, EOF */
return(status);
return(changed);
}


void
init_trust_lst()
{
static int initialized = 0;
int i, len;
char *s;

if (initialized)
return;
for (i = 0; i < 8; ++i)
{ if (trust_lst[i][0])
{ s = PSTR (trust_lst[i]);
if (s != trust_lst[i])
strncpy(trust_lst[i], s, sizeof(trust_lst[0]) - 1);
len = strlen(s);
if (len > trustlst_len)
trustlst_len = len;
}
}
for (i = 0; i < 4; ++i)
{ s = PSTR (legit_lst[i]);
if (s != legit_lst[i])
strncpy(legit_lst[i], s, sizeof(legit_lst[0]) - 1);
len = strlen(s);
if (len > legitlst_len)
legitlst_len = len;
}
++trustlst_len;
++legitlst_len;
initialized = 1;
}

int
show_trust(byte kc_new, byte kc_orig)
{
#ifdef DEBUG
fprintf(pgpout, " %02x", kc_new);
if (kc_new != kc_orig)
{
fprintf(pgpout, " (%02x) ", kc_orig);
return(1);
}
fprintf(pgpout, " ");
return(0);
#else
init_trust_lst();
fprintf(pgpout, "%c%-*s", (kc_new == kc_orig ? ' ' : '!'),
trustlst_len, trust_lst[TRUST_LEV(kc_new)]);
return(kc_new != kc_orig);
#endif
}

int
show_legit(byte kc_new, byte kc_orig)
{
#ifdef DEBUG
return(show_trust(kc_new, kc_orig));
#else
init_trust_lst();
kc_new &= KC_LEGIT_MASK;
kc_orig &= KC_LEGIT_MASK;
fprintf(pgpout, "%c%-*s", (kc_new == kc_orig ? ' ' : '!'),
legitlst_len, legit_lst[kc_new]);
return(kc_new != kc_orig);
#endif
}


/*
* Find all signatures made with a key, fromID is the keyID of this key
* owner_trust is the trust level of this key.
* If a trusted signature makes a key fully legit then signatures made
* with this key are also recursively traced on down the tree.
*/
int
trace_sig_chain(FILE *f, byte *fromID, int owner_trust, int depth)
{
long filepos;
int status;
int trust_count = 0;
byte keyID[KEYFRAGSIZE];
byte sigkeyID[KEYFRAGSIZE];
byte ctb;
byte own_trust, sig_trust;
char userid[256];
int sig_count = 0;
int compromised = 0;
long usertrustpos = 0;
long ownt_pos = 0;

if (max_cert_depth > 8)
max_cert_depth = 8;
if (depth > max_cert_depth)
return(0);
filepos = ftell(f);
rewind(f);
userid[0] = '\0';
while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1)
{
if (status < 0)
return status;

if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
{
compromised = is_compromised(f);
ownt_pos = ftell(f);
if (read_trust(f, &own_trust))
return(ERR_NOTRUST);
userid[0] = '\0';
}
else if (ctb == CTB_USERID)
{
usertrustpos = ftell(f);
trust_count = 0;
}
else if (is_ctb_type(ctb, CTB_SKE_TYPE))
{
if (compromised)
continue;
read_trust(f, &sig_trust);
if (memcmp(sigkeyID, fromID, sizeof(sigkeyID)) == 0)
{
++sig_count;
if (mverbose)
fprintf(pgpout, "%*s > %s\n", 2*depth, "", EXTERNAL(userid));
if (TRUST_LEV(sig_trust) != owner_trust)
{
SET_TRUST(&sig_trust, owner_trust);
}
sig_trust |= KC_CONTIG;
fseek(f, -1L, SEEK_CUR);
fwrite(&sig_trust, 1, 1, f);
fseek(f, 0L, SEEK_CUR);
}

if (sig_trust & KC_CONTIG)
{
trust_count += TRUST_FAC(sig_trust);

switch (set_legit(f, usertrustpos, trust_count))
{
case -1: return(-1);
case 1:
if ((own_trust & (KC_BUCKSTOP|KC_VISITED)) == 0)
{
if (TRUST_LEV(own_trust) == KC_OWNERTRUST_UNDEFINED)
SET_TRUST(&own_trust, ask_owntrust(userid, own_trust));
own_trust |= KC_VISITED;
write_trust_pos(f, own_trust, ownt_pos);
trace_sig_chain(f, keyID, TRUST_LEV(own_trust), depth+1);
}
}
}
}
}
if (mverbose && sig_count == 0) /* no signatures from this user */
fprintf(pgpout, PSTR("%*s (No signatures)\n"), 2*depth, "");
fseek(f, filepos, SEEK_SET);
return(0);
}


int
check_secretkey(FILE *f, long keypos)
{
int status = -1;
unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
unit nsec[MAX_UNIT_PRECISION], esec[MAX_UNIT_PRECISION];
char userid[256];
byte keyID[KEYFRAGSIZE];
long savepos, pktlen;
byte ctb;

if (sec_fp == NULL)
return(-1);

savepos = ftell(f);
fseek(f, keypos, SEEK_SET);
if (readkeypacket(f, FALSE, &ctb, NULL, NULL, n, e,
NULL, NULL, NULL, NULL, NULL, NULL) < 0)
goto ex;
extract_keyID(keyID, n);

do /* get userid */
{ if (readkpacket(f, &ctb, userid, NULL, NULL) < 0)
goto ex;
} while (ctb != CTB_USERID);

if (lookup_by_keyID(sec_fp, keyID) < 0)
{
#if 0
if (!check_only)
{
fprintf(pgpout, PSTR (
"\nAn \"axiomatic\" key is one which does not need certifying by\n\
anyone else. Usually this special status is reserved only for your\n\
own keys, which should also appear on your secret keyring. The owner\n\
of an axiomatic key (who is typically yourself) is \"ultimately trusted\"\n\
by you to certify any or all other keys.\n"));
fprintf(pgpout, PSTR ("\nKey for user ID: \"%s\"\n\
is designated as an \"ultimately-trusted\" introducer, but the key\n\
does not appear in the secret keyring.\n\
Use this key as an ultimately-trusted introducer (y/N)? "), EXTERNAL(userid));
status = (getyesno('n') ? 0 : 1);
}
#else
status = 1;
#endif
}
else
{
long kpos = ftell(sec_fp);
if (readkeypacket(sec_fp, FALSE, &ctb, NULL, NULL, nsec, esec,
NULL, NULL, NULL, NULL, NULL, NULL) < 0)
{
fprintf(pgpout, PSTR("\n\007Cannot read from secret keyring.\n"));
goto ex;
}
if (mp_compare(n, nsec) || mp_compare(e, esec))
{ /* Red Alert! */
fprintf(pgpout, PSTR("\n\007WARNING: Public key for user ID: \"%s\"\n\
does not match the corresponding key in the secret keyring.\n"), EXTERNAL(userid));
fprintf(pgpout, PSTR("This is a serious condition, indicating possible keyring tampering.\n"));
status = -2;
}
else
status = 0;

if (floppy_fp)
{
if (lookup_by_keyID(floppy_fp, keyID) < 0)
{
fprintf(pgpout, PSTR("Public key for: \"%s\"\n\
is not present in the backup keyring '%s'.\n"),
EXTERNAL(userid), floppyring);
}
else
{
pktlen = ftell(sec_fp) - kpos;
fseek(sec_fp, kpos, SEEK_SET);
while (--pktlen >= 0 && getc(sec_fp) == getc(floppy_fp)) ;
if (pktlen != -1)
{
fprintf(pgpout, PSTR("\n\007WARNING: Secret key for: \"%s\"\n\
does not match the key in the backup keyring '%s'.\n"),
EXTERNAL(userid), floppyring);
fprintf(pgpout, PSTR("This is a serious condition, indicating possible keyring tampering.\n"));
status = -2;
}
}
}
}
ex:
fseek(f, savepos, SEEK_SET);
return(status);
}


void
setup_trust()
{ /* initialize trust table */
if (marg_min == 0) /* marginally trusted signatures are ignored */
{
trust_tbl[5] = 0;
trust_tbl[6] = 1;
complete_min = compl_min;
}
else
{
if (marg_min < compl_min)
marg_min = compl_min;
trust_tbl[5] = compl_min;
trust_tbl[6] = marg_min;
complete_min = compl_min * marg_min;
}
trust_tbl[7] = complete_min; /* ultimate trust */
marginal_min = complete_min / 2;
}


/*
* set legit level of a userid
* returns 1 if the key/userid pair is fully legit.
*/
int
set_legit(FILE *f, long trustpos, int trust_count)
{
long filepos;
byte keyctrl;

filepos = ftell(f);
fseek(f, trustpos, SEEK_SET); /* user id trust byte */
if (read_trust(f, &keyctrl) < 0)
return(-1);

if (trust_count < marginal_min)
keyctrl = KC_LEGIT_UNTRUSTED;
else if (trust_count < complete_min)
keyctrl = KC_LEGIT_MARGINAL;
else
keyctrl = KC_LEGIT_COMPLETE;

fseek(f, trustpos, SEEK_SET);
write_trust(f, keyctrl);

fseek(f, filepos, SEEK_SET);

if ((keyctrl & KC_LEGIT_MASK) == KC_LEGIT_COMPLETE)
return(1);
else
return(0);
}


int ask_owntrust(char *userid, byte cur_trust)
/* Ask for a wetware decision from the human on how much to trust
this key's owner to certify other keys. Returns trust value. */
{
char buf[8];

if (check_only)
{ ++undefined_trust;
return(KC_OWNERTRUST_UNDEFINED);
}

fprintf(pgpout,
PSTR("\nMake a determination in your own mind whether this key actually\n\
belongs to the person whom you think it belongs to, based on available\n\
evidence. If you think it does, then based on your estimate of\n\
that person's integrity and competence in key management, answer\n\
the following question:\n"));
fprintf(pgpout, PSTR("\nWould you trust \"%s\"\n\
to act as an introducer and certify other people's public keys to you?\n\
(1=I don't know. 2=No. 3=Usually. 4=Yes, always.) ? "), EXTERNAL(userid));
fflush(pgpout);
getstring(buf, sizeof(buf)-1, TRUE);
switch (buf[0])
{ case '1': return KC_OWNERTRUST_UNKNOWN;
case '2': return KC_OWNERTRUST_NEVER;
case '3': return KC_OWNERTRUST_USUALLY;
case '4': return KC_OWNERTRUST_ALWAYS;
default: return(TRUST_LEV(cur_trust));
}
} /* ask_owntrust */


/*
* compare all key packets in keyring file f with file g
* XXX: untested
*/
int
keyring_cmp(FILE *f, FILE *g)
{
int status, error = 0, badkeys = 0;
byte ctb;
byte keyID[KEYFRAGSIZE];
char userid[256];
long pktlen, keypos = 0;

rewind(f);
while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) == 0)
{
if (is_key_ctb(ctb))
{
pktlen = ftell(f) - keypos;
fseek(f, keypos, SEEK_SET);
if (lookup_by_keyID(g, keyID) < 0)
{
error = 1;
continue;
}
while (--pktlen >= 0 && getc(f) == getc(g)) ;
if (pktlen != -1)
{
error = 2;
++badkeys;
}

}
if (error && ctb == CTB_USERID)
{
switch (error) {
case 1: fprintf(pgpout, PSTR("\n\007Key for user ID \"%s\"\n\
is not present in backup keyring\n"), EXTERNAL(userid));
case 2: fprintf(pgpout, PSTR("\n\007Key for user ID \"%s\"\n\
does not match key in backup keyring\n"), EXTERNAL(userid));
}
error = 0;
}
keypos = ftell(f);
}
if (error)
status = -5;
return(status < 0 ? status : badkeys);
}


int
readkpacket(FILE *f, byte *ctb, char *userid, byte *keyID, byte *sigkeyID)
{
int status;
unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];

status = readkeypacket(f, FALSE, ctb, NULL, userid, n, e,
NULL, NULL, NULL, NULL, sigkeyID, NULL);

if (status < 0)
{
#ifdef DEBUG
if (status < -1)
fprintf(stderr, "readkeypacket returned %d\n", status);
#endif
return(status);
}

if (keyID && is_key_ctb(*ctb))
extract_keyID(keyID, n);

if (userid && *ctb == CTB_USERID)
PascalToC(userid);

return(0);
}

long
lookup_by_keyID(FILE *f, byte *srch_keyID)
{
int status;
long keypos = 0;
byte keyID[KEYFRAGSIZE];
byte ctb;

rewind(f);
while ((status = readkpacket(f, &ctb, NULL, keyID, NULL)) == 0)
{
if (is_key_ctb(ctb) && memcmp(keyID, srch_keyID, KEYFRAGSIZE) == 0)
{
fseek(f, keypos, SEEK_SET);
return(keypos);
}
keypos = ftell(f);
}
return(status);
}


void
show_userid(FILE *f, byte *keyID)
{
long filepos;
char userid[256];

byte ctb;

filepos = ftell(f);
if (lookup_by_keyID(f, keyID) >= 0)
while (readkpacket(f, &ctb, userid, NULL, NULL) == 0)
if (ctb == CTB_USERID)
{
fprintf(pgpout, "%s\n", EXTERNAL(userid));
fseek(f, filepos, SEEK_SET);
return;
}

fprintf(pgpout, "(KeyID: %s)\n",keyIDstring(keyID));
fseek(f, filepos, SEEK_SET);
}

/*
* show the key in file f at file position keypos.
* 'what' controls the info that will be shown:
* SHOW_TRUST: show trust byte info
* SHOW_SIGS: show signatures
* these constants can be or'ed to get both
*/
int
show_key(FILE *f, long keypos, int what)
{
int status;
long filepos;
char userid[256];
unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
byte sigkeyID[KEYFRAGSIZE];
word32 timestamp;
byte ctb, keyctrl;
int userids = 0;
boolean print_trust = FALSE;
int precision = global_precision;

filepos = ftell(f);
fseek(f, keypos, SEEK_SET);
while ((status = readkeypacket(f, FALSE, &ctb, (byte *)×tamp, userid,
n, e, NULL, NULL, NULL, NULL, sigkeyID, &keyctrl)) == 0)
{
if (is_key_ctb(ctb))
{ if (userids)
break;
}
else if (ctb == CTB_KEYCTRL) /* trust bytes only in public keyrings */
{
if (what & SHOW_TRUST)
print_trust = TRUE;
}
else if (ctb == CTB_USERID)
{ if (userids == 0)
{ PascalToC(userid); /* for display */
fprintf(pgpout,PSTR("\nKey for user ID: %s\n"),EXTERNAL(userid));
fprintf(pgpout,PSTR("%d-bit key, Key ID %s, created %s\n"),
countbits(n), key2IDstring(n), cdate(×tamp) );
if (print_trust)
{
switch (TRUST_LEV(keyctrl))
{
case KC_OWNERTRUST_UNDEFINED:
case KC_OWNERTRUST_UNKNOWN:
/* Just don't say anything in this case */
break;
case KC_OWNERTRUST_NEVER: /* untrusted */
fprintf(pgpout, PSTR("This user is untrusted to certify other keys.\n"));
break;
case KC_OWNERTRUST_USUALLY: /* marginal trust */
fprintf(pgpout, PSTR("This user is generally trusted to certify other keys.\n"));
break;
case KC_OWNERTRUST_ALWAYS: /* complete trust */
fprintf(pgpout, PSTR("This user is completely trusted to certify other keys.\n"));
break;
case KC_OWNERTRUST_ULTIMATE: /* axiomatic, ultimate trust */
fprintf(pgpout, PSTR("This axiomatic key is ultimately trusted to certify other keys.\n"));
break;
default:
break;
} /* switch */
}
++userids;
}
else
{ PascalToC(userid);
if (what != 0)
fprintf(pgpout, "\n");
fprintf(pgpout,PSTR("Also known as: %s\n"), EXTERNAL(userid));
}
if (print_trust)
{
read_trust(f, &keyctrl);
switch (keyctrl & KC_LEGIT_MASK)
{
case 0: /* undefined certification level */
case 1: /* uncertified */
fprintf(pgpout, PSTR("This key/userID association is not certified.\n"));
break;
case 2: /* marginal certification */
fprintf(pgpout, PSTR("This key/userID association is marginally certified.\n"));
break;
case 3: /* complete certification */
fprintf(pgpout, PSTR("This key/userID association is fully certified.\n"));
break;
default: /* can't get here, right? */
break;
} /* switch */
} /* print_trust */
}
else if ((what & SHOW_SIGS) && is_ctb_type(ctb, CTB_SKE_TYPE))
{
if (print_trust)
{
read_trust(f, &keyctrl);
switch (TRUST_LEV(keyctrl))
{
case KC_SIGTRUST_UNDEFINED: /* undefined trust level */
case KC_SIGTRUST_UNKNOWN:
/* Just don't say anything in this case */
fprintf(pgpout, PSTR(" Questionable certification from:\n "));
break;
case KC_SIGTRUST_UNTRUSTED: /* untrusted */
fprintf(pgpout, PSTR(" Untrusted certification from:\n "));
break;
case KC_SIGTRUST_MARGINAL: /* marginal trust */
fprintf(pgpout, PSTR(" Generally trusted certification from:\n "));
break;
case KC_SIGTRUST_COMPLETE: /* complete trust */
fprintf(pgpout, PSTR(" Completely trusted certification from:\n "));
break;
case KC_SIGTRUST_ULTIMATE: /* axiomatic, ultimate trust */
fprintf(pgpout, PSTR(" Axiomatically trusted certification from:\n "));
break;
default: /* can't get here, right? */
break;
} /* switch */
}
else
fprintf(pgpout, PSTR(" Certified by: "));
show_userid(f, sigkeyID);
}
}
if (status == -1 && userids)
status = 0;
set_precision(precision);
fseek(f, filepos, SEEK_SET);
return(status);
}


void
write_trust_pos(FILE *f, byte keyctrl, long pos)
{
long fpos;

fpos = ftell(f);
fseek(f, pos, SEEK_SET);
write_trust(f, keyctrl);
fseek(f, fpos, SEEK_SET);
}

int
read_trust(FILE *f, byte *keyctrl)
{
unsigned char buf[3];

if (fread(buf, 1, 3, f) != 3)
return -1;
if (buf[0] != CTB_KEYCTRL)
{
if (is_ctb(buf[0]))
return(ERR_NOTRUST);
else
return(-3); /* bad data */
}
if (buf[1] != 1) /* length must be 1 */

return(-3);
if (keyctrl)
*keyctrl = buf[2];
return(0);
}


  3 Responses to “Category : C Source Code
Archive   : PGP20SRC.ZIP
Filename : KEYMAINT.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/