📄 pgpk.c
字号:
/* Write out new results */
if (needwritesec) {
ringSetFreeze (secset);
mainRingNewSet (sec, PGP_WRITETRUST_SEC, secset);
secset = 0; /* Don't destroy this */
fprintf (stderr,
"Private keyring updated.\n");
}
if (needwritepub) {
ringSetFreeze (pubset);
mainRingNewSet (pub, PGP_WRITETRUST_PUB, pubset);
pubset = 0; /* Don't destroy this */
fprintf (stderr,
"Public keyring updated.\n");
}
cleanup:
if (seckey)
pgpSecKeyDestroy(seckey);
if (subkey)
pgpSecKeyDestroy(subkey);
if (pubset)
ringSetDestroy(pubset);
if (secset)
ringSetDestroy(secset);
if (pubring)
ringSetDestroy(pubring);
if (secring)
ringSetDestroy(secring);
return err;
}
static int
doKeyEdit (struct PgpEnv *env, struct Flags *flags, int argc, char *argv[],
struct PgpTtyUI *ui_arg)
{
struct RingSet *pubring = NULL, *secring = NULL;
union RingObject *obj;
char const *pub, *sec;
char const *prep = "to edit";
int err;
(void)flags; /* make the compiler happy */
mainOpenPubSec(env, &pub, &pubring, &sec, &secring, stderr);
if (!pubring || !secring) {
fprintf (stderr, "No keys in pubring or secring\n");
return 0;
}
loadAllKeys(env, 1, 0);
/* Select object to sign */
err = selectRingObject(env, argc, argv, pub, pubring, RINGTYPE_KEY,
prep, stderr, &obj);
if (err <= 0)
return err;
fprintf (stderr, "\n");
ringKeyPrint (stderr, pubring, obj, 1);
fprintf (stderr, "\n");
if (ringKeyIsSec(allkeys, obj))
return doKeyEditSelf(env, flags, obj, pub, pubring,
sec, secring, ui_arg);
else
return doKeyEditOthers(env, flags, obj, pub, pubring,
sec, secring, ui_arg);
}
/*
* This handles key, user ID (with -ru), or signature (with -rs) removal.
*/
static int
doKeyRemove (struct PgpEnv *env, struct Flags *flags, int argc, char *argv[],
struct PgpTtyUI *ui_arg)
{
struct RingSet *pubring = NULL;
struct RingSet *secring = NULL;
struct RingSet *keyfile = NULL, *seckeyfile = NULL;
union RingObject *obj;
char const *pub, *sec;
int numseckeys = 0;
int err = 0;
int removelevel;
const char *prep = "to be removed";
const char *typename;
int removed = 0;
/* Distinguish what we are to remove */
if (flags->argc && strchr(flags->args, 's')) {
removelevel = RINGTYPE_SIG; /* signature */
typename = "signature";
} else if (flags->argc && strchr(flags->args, 'u')) {
removelevel = RINGTYPE_NAME; /* user id */
typename = "user ID";
} else {
removelevel = RINGTYPE_KEY; /* key */
typename = "key";
}
/* Open pub and sec key rings */
mainOpenPubSec(env, &pub, &pubring, &sec, &secring, stderr);
if (!pubring) {
fprintf (stderr,
"No keys in pubring\n");
goto cleanup;
}
loadAllKeys(env, 1, 0);
/* Select object to remove */
fprintf (stderr, "\n");
err = selectRingObject(env, argc, argv, pub, pubring, removelevel,
prep, stderr, &obj);
if (err <= 0)
goto cleanup;
/* err holds number of possible objects at that level */
if (removelevel == RINGTYPE_NAME && err == 1) {
err = 0;
fprintf (stderr,
"Selected key has only one user ID, can't be selected %s\n", prep);
goto cleanup;
}
/* Confirm removal */
fprintf(stderr,
"\nThe following %s has been selected %s:\n", typename, prep);
objPrint(env, obj, stderr, NULL);
/* See if key is on private ring too */
numseckeys = secring ? ringSetIsMember(secring, obj) : 0;
if (numseckeys) {
fprintf(stderr,
"\nThis %s is also present in the private keyring.\n", typename);
fprintf(stderr,
"Removing it will remove it from both the public and private keyrings.\n"\
"Do you want to remove it from both keyrings (y/N)? ");
} else {
fprintf (stderr,
"\nAre you sure you want this %s %s (y/N)? ", typename, prep);
}
if (!pgpTtyGetBool(0, stderr)) {
fprintf (stderr,
"Removal cancelled.\n");
err = 0;
goto cleanup;
}
fprintf (stderr, "\n");
/* Perform removal, but don't write back yet */
keyfile = ringSetCreate (ringpool);
if (!keyfile) {
err = ringPoolError(ringpool)->error;
goto cleanup;
}
err = ringSetAddSet(keyfile, pubring);
if (err < 0)
goto cleanup;
err = ringSetRemObject(keyfile, obj);
if (err < 0)
goto cleanup;
ringSetFreeze (keyfile);
removed = 1;
if (numseckeys) {
/* Remove from private key ring, don't write back yet */
seckeyfile = ringSetCreate (ringpool);
if (!seckeyfile) {
err = ringPoolError(ringpool)->error;
goto cleanup;
}
err = ringSetAddSet(seckeyfile, secring);
if (err < 0)
goto cleanup;
err = ringSetRemObject(seckeyfile, obj);
if (err < 0)
goto cleanup;
ringSetFreeze (seckeyfile);
}
ringObjectRelease(obj);
/* Write out results */
mainRingNewSet (pub, PGP_WRITETRUST_PUB, keyfile);
keyfile = NULL; /* Don't destroy this */
if (err < 0) {
fprintf (stderr,
"Error - unable to update key file!\n");
goto cleanup;
}
if (numseckeys) {
mainRingNewSet (sec, PGP_WRITETRUST_SEC, seckeyfile);
seckeyfile = NULL; /* Don't destroy this */
if (err < 0) {
fprintf (stderr,
"Error - unable to update private key file!\n");
goto cleanup;
}
}
/* success */
err = 0;
cleanup:
if (seckeyfile)
ringSetDestroy(seckeyfile);
if (keyfile)
ringSetDestroy(keyfile);
if (pubring)
ringSetDestroy(pubring);
if (secring)
ringSetDestroy(secring);
/* If no error and something was removed, do a maintenance pass.
This causes the (new) public keyring to be reopened and re-read,
but gives us the correct community of keys to be validated. */
if (err == 0 && removed) {
/* Close and write out current keyrings before reopening */
ringSetDestroy(allkeys);
allkeys = 0;
mainCloseKeyrings(1 /*update*/, 1 /*newvers*/);
reloadAllKeys (env, 0, 1);
err = mainDoMaint ((void *) ui_arg, allkeys, 0, NULL);
fprintf (stderr,
"This %s has now been removed from the public key ring.\n", typename);
if (numseckeys) {
fprintf (stderr,
"This %s has also been removed from the private key ring.\n", typename);
}
}
return err;
}
/*
* Issue a signature on a userID.
*/
static int
doKeySign (struct PgpEnv *env, struct Flags *flags, int argc, char *argv[],
struct PgpTtyUI *ui_arg)
{
struct RingSet *pubring = NULL;
struct RingSet *newpub = NULL;
struct RingSet *tmpring;
struct RingIterator *iter;
struct PgpSigSpec *sigspec = NULL;
struct PgpSecKey *secretKey = NULL;
union RingObject *obj=NULL, *ringobj = NULL;
char const *pub;
int level;
int err;
const char *prep = "to be signed";
byte keyid[8];
byte pkalg;
int sigtype = PGP_SIGTYPE_KEY_GENERIC;
char const *myname = pgpenvGetString (env, PGPENV_MYNAME,
NULL, NULL);
(void)flags;
/* Open pub key ring */
mainOpenPubSec(env, &pub, &pubring, NULL, NULL, stderr);
if (!pubring) {
fprintf (stderr,
"No keys in pubring\n");
return 0;
}
loadAllKeys(env, 1, 0);
/* Find secret key, make sure it signs */
ringobj = ringLatestSecret (allkeys, myname, time(NULL),
PGP_PKUSE_SIGN);
if (!ringobj) {
fprintf (stderr,
"Cannot find private key suitable for signing: %s\n", myname);
ringSetDestroy(pubring);
return 0;
}
secretKey = ringSecSecKey (allkeys, ringobj, PGP_PKUSE_SIGN);
if (!secretKey) {
fprintf (stderr, "Cannot convert to private key\n");
ringSetDestroy(pubring);
return 0;
}
if (!secretKey->sign) {
fprintf (stderr, "Private Key is not a signature key\n");
ringSetDestroy(pubring);
return 0;
}
/* Data to check for duplicate sigs below */
memcpy(keyid, secretKey->keyID, sizeof(keyid));
pkalg = secretKey->pkAlg;
/* Select object to sign */
err = selectRingObject(env, argc, argv, pub, pubring, RINGTYPE_NAME,
prep, stderr, &obj);
if (err <= 0)
return err;
/* Make sure it doesn't already have a sig on it from this key */
iter = ringIterCreate(pubring);
level = ringIterSeekTo(iter, obj);
if (level < 0) {
ringSetDestroy(pubring);
return level;
}
++level;
while (ringIterNextObject(iter, level) > 0) {
byte sigid[8];
byte sigpkalg;
union RingObject *sig = ringIterCurrentObject(iter, level);
pgpAssert(sig);
if (ringObjectType(sig) != RINGTYPE_SIG)
continue;
ringSigID8(pubring, sig, &sigpkalg, sigid);
if (sigpkalg==pkalg &&
memcmp(sigid, keyid, sizeof(sigid))==0 &&
ringSigType(pubring, sig) == sigtype) {
/* Duplicate */
fprintf (stderr,
"User ID is already signed by your private key\n");
ringIterDestroy(iter);
ringSetDestroy(pubring);
return 0;
}
}
ringIterDestroy(iter);
/* Confirm signature */
objPrint(env, obj, stderr, NULL);
fprintf(stderr,
"\n\n"\
"READ CAREFULLY: Based on your own direct first-hand knowledge, are\n"\
"you absolutely certain that you are prepared to solemnly certify that\n"\
"the above public key actually belongs to the user specified by the\n"\
"above user ID (y/N)? ");
if (!pgpTtyGetBool(0, stderr)) {
fprintf (stderr,
"Key sign operation cancelled.\n");
ringSetDestroy(pubring);
return 0;
}
ui_arg->ringset = allkeys;
err = pgpTtyUnlockSeckey (ui_arg, ringobj, secretKey,
"\nYou need a pass phrase to unlock your private key.\n");
ringObjectRelease (ringobj);
if (err) {
fprintf (stderr, "Cannot unlock private key\n");
ringSetDestroy(pubring);
return 0;
}
/* Actually do the signature */
sigspec = pgpSigSpecCreate (env, secretKey, sigtype);
if (!sigspec) {
ringSetDestroy(pubring);
return PGPERR_NOMEM;
}
newpub = ringSetCreate (ringpool);
if (!newpub) {
pgpSigSpecDestroy(sigspec);
ringSetDestroy(pubring);
return PGPERR_NOMEM;
}
ringSetAddSet (newpub, pubring);
ringSetDestroy(pubring);
pubring = NULL;
if (!rng)
rng = pgpRandomCreate ();
err = ringSignObject (newpub, obj, sigspec, rng);
pgpSigSpecDestroy(sigspec);
ringSetFreeze(newpub);
if (err < 0)
return err;
/* Do maintenance pass */
fprintf (stderr, "\n");
reloadAllKeys (env, 0, 1);
tmpring = ringSetUnion(allkeys, newpub);
ringSetDestroy(allkeys);
allkeys = tmpring;
err = mainDoMaint ((void *) ui_arg, allkeys, 1, allkeys);
if (err < 0)
return err;
/* Write out results */
mainRingNewSet (pub, PGP_WRITETRUST_PUB, newpub);
newpub = NULL; /* Don't destroy this */
fprintf (stderr,
"Key signature certificate added.\n");
return 0;
}
/*
* Return true if a key has been revoked.
*/
static int
mainKeyRevoked (struct RingSet const *set, union RingObject *obj)
{
struct RingIterator *iter;
byte keyid[8], keypkalg;
int level;
pgpAssert (ringObjectType(obj) == RINGTYPE_KEY);
ringKeyID8(set, obj, &keypkalg, keyid);
iter = ringIterCreate(set);
level = ringIterSeekTo(iter, obj);
if (level < 0) {
ringIterDestroy(iter);
return level;
}
++level;
while (ringIterNextObject(iter, level) > 0) {
byte sigid[8];
byte sigpkalg;
int sigtype;
union RingObject *sig = ringIterCurrentObject(iter, level);
pgpAssert(sig);
if (ringObjectType(sig) != RINGTYPE_SIG)
continue;
ringSigID8(set, sig, &sigpkalg, sigid);
if (memcmp(keyid,sigid,sizeof(keyid))!=0 ||
sigpkalg != keypkalg)
continue;
sigtype = ringSigType(set, sig);
if (sigtype == PGP_SIGTYPE_KEY_COMPROMISE) {
ringIterDestroy(iter);
return 1; /* yes, it is revoked */
}
}
ringIterDestroy(iter);
return 0; /* no, it is not revoked */
}
/*
* Given a userID signature, return true if it has been revoked.
* @@@ Better to worry more about validity here?
*/
static int
mainSigRevoked (struct RingSet const *set, union RingObject *obj)
{
struct RingIterator *iter;
byte keyid[8], pkalg;
int level;
pgpAssert (ringObjectType(obj) == RINGTYPE_SIG);
ringSigID8(set, obj, &pkalg, keyid);
/* Prepare to iterate */
iter = ringIterCreate(set);
if (!iter)
return PGPERR_NOMEM;
level = ringIterSeekTo(iter, obj);
if (level < 0) {
ringIterDestroy(iter);
return level;
}
/* Loop over all sigs on the name */
ringIterRewind(iter, level);
while ((level = ringIterNextObject (iter, level)) > 0) {
union RingObject *sig = ringIterCurrentObject(iter, level);
byte sigpkalg, sigid[8];
pgpAssert(sig);
if (ringObjectType(sig) != RINGTYPE_SIG)
continue;
ringSigID8(set, sig, &sigpkalg, sigid);
if (sigpkalg==pkalg &&
memcmp(sigid, keyid, sizeof(sigid))==0) {
int type = ringSigType(set, sig);
if (type == PGP_SIGTYPE_KEY_UID_REVOKE) {
ringIterDestroy(iter);
ringObjectRelease(sig);
return 1; /* revocation found */
}
}
}
ringIterDestroy(iter);
return 0; /* no revocation found */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -