📄 pgpkeyman.c
字号:
expiration, NULL, 0, passphrase,
masterpass, progress, arg);
}
/* Disable the key. If key is not stored in a writeable KeySet, copy it
locally. Private keys cannot be disabled. */
PGPError
pgpDisableKey (PGPKey *key)
{
PGPKeyDB *keys = NULL;
struct RingSet *allset = NULL, *addset = NULL;
union RingObject *keyobj;
PGPError error = PGPERR_OK;
pgpa(pgpaPGPKeyValid(key));
if (pgpKeyIsDead (key))
return PGPERR_BADPARAM;
keys = key->keyDB;
keyobj = key->key;
allset = pgpKeyDBRingSet (keys);
/* Axiomatic keys cannot be disabled, but plain old private
keys can (because they may belong to someone else). */
if (ringKeyAxiomatic (allset, keyobj))
return PGPERR_BADPARAM;
if (!(*keys->isMutable) (keys))
return PGPERR_KEYDB_KEYDBREADONLY;
if ((error = pgpCopyKey (allset, keyobj, &addset)) != PGPERR_OK)
return error;
if (!ringKeyDisabled (allset, keyobj)) {
if (!(*keys->objIsMutable) (keys, keyobj)) {
if ((error = pgpAddObjects (keys, addset)) != PGPERR_OK)
goto cleanup;
}
ringKeyDisable (allset, keyobj);
pgpKeyDBChanged (keys, addset);
}
cleanup:
if (addset)
ringSetDestroy (addset);
return error;
}
/* Enable the key. */
PGPError
pgpEnableKey (PGPKey *key)
{
PGPKeyDB *keys;
struct RingSet *allset, *addset;
union RingObject *keyobj;
PGPError error = PGPERR_OK;
pgpa(pgpaPGPKeyValid(key));
if (pgpKeyIsDead (key))
return PGPERR_BADPARAM;
keys = key->keyDB;
keyobj = key->key;
allset = pgpKeyDBRingSet (keys);
if (!(*keys->isMutable) (keys))
return PGPERR_KEYDB_KEYDBREADONLY;
if (ringKeyDisabled (allset, keyobj)) {
if ((error = pgpCopyKey (allset, keyobj, &addset)) != PGPERR_OK)
return error;
ringKeyEnable (allset, keyobj);
pgpKeyDBChanged (keys, addset);
ringSetDestroy (addset);
}
return PGPERR_OK;
}
/* Change the passphrase. If the new passphrase is the same as the
old passphrase, we still unlock the key as the user may be trying to
set the key's isAxiomatic flag. */
static PGPError
pgpChangePassphraseInternal (PGPKeyDB *keyDB, RingSet *ringset,
RingObject *keyobj, RingObject *masterkeyobj,
char *oldphrase, char *newphrase)
{
unsigned long validity;
struct RingSet *addset = NULL;
union RingObject *newsecobj, *oldsecobj = NULL;
struct PgpKeySpec *keyspec = NULL;
PGPError error = PGPERR_OK;
struct PgpSecKey *seckey = NULL;
PgpVersion version;
int newphraselen = 0;
Boolean locked = 0;
if (oldphrase && strlen (oldphrase) == 0)
oldphrase = NULL;
if (newphrase && (newphraselen = strlen (newphrase)) == 0)
newphrase = NULL;
if (!(*keyDB->isMutable) (keyDB))
return PGPERR_KEYDB_KEYDBREADONLY;
if (!ringKeyIsSec (ringset, keyobj))
return PGPERR_NO_SECKEY;
/* Find old secret object */
{
RingIterator *riter;
int level;
riter = ringIterCreate (ringset);
if (!riter)
return PGPERR_NOMEM;
level = ringIterSeekTo (riter, keyobj);
pgpAssert (level>0);
while (ringIterNextObject (riter, level+1) == level+1) {
oldsecobj = ringIterCurrentObject (riter, level+1);
if (ringObjectType(oldsecobj) == RINGTYPE_SEC)
break;
}
ringIterDestroy (riter);
pgpAssert (oldsecobj);
}
/* Does the caller know the current passphrase? */
seckey = ringSecSecKey (ringset, oldsecobj, 0);
if (!seckey)
return ringSetError(ringset)->error;
if (pgpSecKeyIslocked (seckey)) {
locked = 1;
if (!oldphrase) {
error = PGPERR_KEYDB_BADPASSPHRASE;
goto cleanup;
}
error = pgpSecKeyUnlock (seckey, pgpEnv, oldphrase,
strlen (oldphrase));
if (error != 1) {
if (error == 0)
error = PGPERR_KEYDB_BADPASSPHRASE;
goto cleanup;
}
}
/* All done if passphrase has not changed */
if ((!oldphrase && !newphrase) ||
(oldphrase && locked && newphrase &&
strcmp (oldphrase, newphrase) == 0)) {
error = PGPERR_OK;
goto cleanup;
}
error = pgpCopyKey (ringset, keyobj, &addset);
if (error)
goto cleanup;
error = pgpSecKeyChangeLock (seckey, pgpEnv, pgpRng,
newphrase, newphraselen);
if (error)
goto cleanup;
keyspec = pgpKeySpecCreate (pgpEnv);
if (!keyspec) {
error = PGPERR_NOMEM;
goto cleanup;
}
/* We need to make this keyspec just like the existing one */
pgpKeySpecSetCreation (keyspec, ringKeyCreation (ringset, keyobj));
/* Fix "version bug", don't change version from earlier one. */
version = ringSecVersion (ringset, keyobj);
pgpKeySpecSetVersion (keyspec, version);
validity = ringKeyExpiration (ringset, keyobj);
if (validity != 0) {
validity -= ringKeyCreation (ringset, keyobj);
validity /= 3600*24;
}
pgpKeySpecSetValidity (keyspec, (word16) validity);
newsecobj = ringCreateSec (addset, masterkeyobj, seckey, keyspec,
seckey->pkAlg);
if (!newsecobj) {
error = ringSetError(addset)->error;
goto cleanup;
}
pgpKeySpecDestroy (keyspec); keyspec = NULL;
pgpSecKeyDestroy (seckey); seckey = NULL;
error = pgpAddObjects (keyDB, addset);
/* This step is necessary for the RingFile to close cleanly */
if (!error) {
/*
* pgpRemoveObject not appropriate since this is not an object
* type that it knows how to deal with.
*/
(keyDB->remove) (keyDB, oldsecobj);
}
cleanup:
if (seckey)
pgpSecKeyDestroy (seckey);
if (addset)
ringSetDestroy (addset);
if (keyspec)
pgpKeySpecDestroy (keyspec);
return error;
}
PGPError
pgpChangePassphrase (PGPKey *key, char *oldphrase, char *newphrase)
{
RingSet *ringset;
PGPError error;
pgpa(pgpaPGPKeyValid(key));
ringset = pgpKeyDBRingSet (key->keyDB);
error = pgpChangePassphraseInternal (key->keyDB, ringset, key->key, NULL,
oldphrase, newphrase);
if (!error)
ringKeySetAxiomatic (ringset, key->key);
return error;
}
PGPError
pgpChangeSubKeyPassphrase (PGPSubKey *subkey,
char *oldphrase, char *newphrase)
{
RingSet *ringset;
pgpa(pgpaPGPSubKeyValid(subkey));
CHECKREMOVED(subkey);
ringset = pgpKeyDBRingSet (subkey->key->keyDB);
return pgpChangePassphraseInternal (subkey->key->keyDB, ringset,
subkey->subKey,
subkey->key->key,
oldphrase, newphrase);
}
/* Remove a subkey */
PGPError
pgpRemoveSubKey (PGPSubKey *subkey)
{
PGPKeyDB *keys;
struct RingSet *allset;
union RingObject *subkeyobj;
pgpa(pgpaPGPSubKeyValid(subkey));
CHECKREMOVED(subkey);
keys = subkey->key->keyDB;
if (!(*keys->isMutable) (keys))
return PGPERR_KEYDB_KEYDBREADONLY;
allset = pgpKeyDBRingSet (keys);
subkeyobj = subkey->subKey;
if (!(*keys->objIsMutable) (keys, subkeyobj))
return PGPERR_KEYDB_OBJECTREADONLY;
return pgpRemoveObject (keys, subkeyobj);
}
PGPError
pgpRevokeSubKey (PGPSubKey *subkey, char *passphrase)
{
PGPKeyDB *keys;
struct RingSet *allset, *addset;
union RingObject *subkeyobj, *keyobj;
PGPError error = PGPERR_OK;
pgpa(pgpaPGPSubKeyValid(subkey));
CHECKREMOVED(subkey);
keys = subkey->key->keyDB;
subkeyobj = subkey->subKey;
keyobj = subkey->key->key;
if (pgpSubKeyIsDead (subkey))
return PGPERR_OK;
if (!(*keys->isMutable) (keys))
return PGPERR_KEYDB_KEYDBREADONLY;
allset = pgpKeyDBRingSet (keys);
if (!ringKeyIsSec (allset, keyobj))
return PGPERR_NO_SECKEY; /* not our key */
error = pgpCopyKey (allset, keyobj, &addset);
if (error)
return error;
/* Note special subkey revocation sigtype */
error = pgpCertifyObject (subkeyobj, addset, keyobj, allset,
PGP_SIGTYPE_KEY_SUBKEY_REVOKE, passphrase, FALSE);
if (error) {
ringSetDestroy (addset);
return error;
}
/* Update the KeyDB */
error = pgpAddObjects (keys, addset);
ringSetDestroy (addset);
return error;
}
/* Remove a User ID. If the KeySet is read-only, or the UserID object
itself is read-only, we return an error. */
PGPError
pgpRemoveUserID (PGPUserID *userid)
{
PGPKeyDB *keys;
PGPUserID *uidtmp;
int uidcount = 0;
struct RingSet *allset;
union RingObject *nameobj;
pgpa(pgpaPGPUserIDValid(userid));
CHECKREMOVED(userid);
/* Cannot remove only UserID */
for (uidtmp = (PGPUserID *) userid->key->userIDs.next;
uidtmp != (PGPUserID *) &userid->key->userIDs;
uidtmp = uidtmp->next) {
if (!uidtmp->removed)
uidcount++;
}
if (uidcount == 1)
return PGPERR_BADPARAM;
keys = userid->key->keyDB;
if (!(*keys->isMutable) (keys))
return PGPERR_KEYDB_KEYDBREADONLY;
allset = pgpKeyDBRingSet (keys);
nameobj = userid->userID;
if (!(*keys->objIsMutable) (keys, nameobj))
return PGPERR_KEYDB_OBJECTREADONLY;
return pgpRemoveObject (keys, nameobj);
}
/*
* Add a new User ID to a key. User IDs cannot be added to other than the
* user's own keys. The new User ID is added to the end of the list. To
* make it the primary User ID, call pgpSetPrimaryUserID() below.
*/
PGPError
pgpAddUserID (PGPKey *key, char *name, int name_len, char *passphrase)
{
PGPKeyDB *keys;
PGPUserID *userid;
struct RingSet *allset, *addset;
union RingObject *keyobj, *nameobj;
PGPError error;
pgpa(pgpaPGPKeyValid(key));
if (pgpKeyIsDead (key))
return PGPERR_BADPARAM;
keys = key->keyDB;
if (!(*keys->isMutable) (keys))
return PGPERR_KEYDB_KEYDBREADONLY;
allset = pgpKeyDBRingSet (keys);
keyobj = key->key;
/* Can only add User ID to our own keys */
if (!ringKeyIsSec (allset, keyobj))
return PGPERR_NO_SECKEY;
error = pgpCopyKey (allset, keyobj, &addset);
if (error)
return error;
nameobj = ringCreateName (addset, keyobj, name, name_len);
if (!nameobj) {
error = ringSetError(addset)->error;
ringSetDestroy (addset);
return error;
}
/* ringCreateName will return a duplicate nameobj if
the name already exists for this key. Check the
list of PGPUserID objects to see if the nameobj
is already referenced. */
for (userid = (PGPUserID *) key->userIDs.next;
userid != (PGPUserID *) &key->userIDs;
userid = userid->next) {
if (!userid->removed && userid->userID == nameobj) {
ringSetDestroy (addset);
return PGPERR_KEYDB_DUPLICATE_USERID;
}
}
/* Must self-certify here */
error = pgpCertifyObject (nameobj, addset, keyobj, allset,
PGP_SIGTYPE_KEY_GENERIC, passphrase, TRUE);
if (error) {
ringSetDestroy (addset);
return error;
}
error = pgpAddObjects (keys, addset);
ringSetDestroy (addset);
return error;
}
/* Make the given User ID the primary User ID of the key */
PGPError
pgpSetPrimaryUserID (PGPUserID *userid)
{
PGPKeyDB *keys;
PGPKey *key;
struct RingSet *allset, *addset;
PGPError error;
pgpa(pgpaPGPUserIDValid(userid));
CHECKREMOVED(userid);
key = userid->key;
if (pgpKeyIsDead (key))
return PGPERR_BADPARAM;
keys = key->keyDB;
if (!(*keys->isMutable) (keys))
return PGPERR_KEYDB_KEYDBREADONLY;
allset = pgpKeyDBRingSet (keys);
error = pgpCopyKey (allset, key->key, &addset);
if (error)
return error;
/* Raise the name to the top */
ringRaiseName (addset, userid->userID);
/* Rearrange the circularly-linked list of userids */
userid->prev->next = userid->next;
userid->next->prev = userid->prev;
userid->prev = (PGPUserID *)&key->userIDs;
userid->next = (PGPUserID *)key->userIDs.next;
userid->next->prev = userid;
userid->prev->next = userid;
error = pgpKeyDBChanged(keys, addset);
ringSetDestroy (addset);
return error;
}
/* Certify a User ID. Do not allow duplicate certification. If UserID
is already certified, but revoked, the old cert can
be removed and the UserID then recertified. */
PGPError
pgpCertifyUserID (PGPUserID *userid, PGPKey *certifying_key, char *passphrase)
{
PGPKeyDB *keys;
struct RingSet *ringset, *addset, *signerset;
union RingObject *keyobj, *nameobj, *sigobj;
struct RingIterator *iter;
PGPError error = PGPERR_OK;
pgpa(pgpaPGPUserIDValid(userid));
CHECKREMOVED(userid);
if (pgpKeyIsDead (userid->key))
return PGPERR_BADPARAM;
if (certifying_key)
pgpa(pgpaPGPKeyValid(certifying_key));
if (userid->removed)
return PGPERR_BADPARAM;
keys = userid->key->keyDB;
if (!(*keys->isMutable) (keys))
return PGPERR_KEYDB_KEYDBREADONLY;
ringset = pgpKeyDBRingSet (keys);
nameobj = userid->userID;
/* If certifying key was not passed, get the default */
if (!certifying_key) {
certifying_key = pgpGetDefaultPrivateKeyInternal (keys);
if (!certifying_key)
return PGPERR_NO_SECKEY;
}
if (pgpKeyIsDead (certifying_key)) {
return PGPERR_KEYDB_CERTIFYINGKEY_DEAD;
}
/* Get RingSet for certifying key */
if (certifying_key->keyDB != keys)
signerset = pgpKeyDBRingSet (certifying_key->keyDB);
else
signerset = ringset;
keyobj = certifying_key->key;
/* Check for duplicate certificate. There may be some
old revocation certs still laying around, which we
should ignore. */
iter = ringIterCreate (ringset);
if (!iter)
return ringSetError(ringset)->error;
ringIterSeekTo (iter, nameobj);
while ((error = ringIterNextObject (iter, 3)) > 0) {
sigobj = ringIterCurrentObject (iter, 3);
if (ringSigMaker (ringset, sigobj, signerset) == keyobj &&
ringSigType (ringset, sigobj) != PGP_SIGTYPE_KEY_UID_REVOKE) {
error = PGPERR_KEYDB_DUPLICATE_CERT;
break;
}
}
ringIterDestroy (iter);
if (error)
return error;
error = pgpCopyKey (ringset, nameobj, &addset);
if (error)
return error;
error = pgpCertifyObject (nameobj, addset, keyobj, signerset,
PGP_SIGTYPE_KEY_GENERIC, passphrase, FALSE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -