📄 pgpkeyman.c
字号:
/*
* pgpKeyMan.c -- Key Manipulation functions
*
* Copyright (C) 1996,1997 Pretty Good Privacy, Inc. All rights reserved.
*
* $Id: pgpKeyMan.c,v 1.61.2.6 1997/06/07 09:50:26 mhw Exp $
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pgpKDBint.h"
#include "pgpDebug.h"
#include "pgpRngPub.h"
#include "pgpRngRead.h"
#include "pgpPubKey.h"
#include "pgpRndom.h"
#include "pgpSigSpec.h"
#include "pgpKeySpec.h"
#include "pgpTrstPkt.h"
#include "pgpTrust.h"
#include "pgpHash.h"
#include "pgpEnv.h"
#include "bn.h"
/* INTERNAL FUNCTIONS */
/* Internal function for certifying a key or userid. Object to be signed
must be in dest. Signing key should be in src. selfsig should be
set for self-certifying names. */
static PGPError
pgpCertifyObject (union RingObject *to_sign, struct RingSet *dest,
union RingObject *signer, struct RingSet *src,
byte sigtype, char *passphrase, Boolean selfsig)
{
struct PgpSecKey *seckey = NULL;
struct PgpSigSpec *sigspec = NULL;
PGPError error = PGPERR_OK;
if (passphrase && strlen (passphrase) == 0)
passphrase = NULL;
if (!signer || !ringKeyIsSec (src, signer) ||
!(ringKeyUse (src, signer) & PGP_PKUSE_SIGN))
return PGPERR_NO_SECKEY;
seckey = ringSecSecKey (src, signer, PGP_PKUSE_SIGN);
if (!seckey)
return ringSetError(src)->error;
if (pgpSecKeyIslocked (seckey)) {
if (!passphrase) {
pgpSecKeyDestroy (seckey);
return PGPERR_KEYDB_BADPASSPHRASE;
}
error = pgpSecKeyUnlock (seckey, pgpEnv, passphrase,
strlen (passphrase));
if (error != 1) {
pgpSecKeyDestroy (seckey);
if (error == 0)
error = PGPERR_KEYDB_BADPASSPHRASE;
return error;
}
}
ringKeySetAxiomatic (src, signer); /* user knows the passphrase */
sigspec = pgpSigSpecCreate (pgpEnv, seckey, sigtype);
if (!sigspec) {
pgpSecKeyDestroy (seckey);
return PGPERR_NOMEM;
}
if (seckey->pkAlg > PGP_PKALG_RSA + 2 &&
sigtype == PGP_SIGTYPE_KEY_GENERIC && selfsig) {
/* Propagate sig subpacket information */
byte const *p;
size_t plen;
pgpSigSpecSetVersion (sigspec, PGPVERSION_3);
if ((p=ringKeyFindSubpacket (signer, src, SIGSUB_PREFERRED_ALGS, 0,
&plen, NULL, NULL, NULL, NULL, NULL)) != 0) {
pgpSigSpecSetPrefAlgs (sigspec, p, plen);
}
if (ringKeyExpiration (src, signer)) {
word32 period = ringKeyExpiration (src, signer) -
ringKeyCreation (src, signer);
pgpSigSpecSetKeyExpiration (sigspec, period);
}
}
error = ringSignObject (dest, to_sign, sigspec, pgpRng);
pgpSecKeyDestroy (seckey);
pgpSigSpecDestroy (sigspec);
return error;
}
/* Check for a 'dead' key. A dead key is revoked or expired.
There's not much you can do with such a key. */
static Boolean
pgpKeyIsDead (PGPKey *key)
{
Boolean revoked, expired;
pgpGetKeyBoolean (key, kPGPKeyPropIsRevoked, &revoked);
pgpGetKeyBoolean (key, kPGPKeyPropIsExpired, &expired);
return (revoked || expired);
}
/* Same for subkey... */
static Boolean
pgpSubKeyIsDead (PGPSubKey *subkey)
{
Boolean revoked, expired;
pgpGetSubKeyBoolean (subkey, kPGPKeyPropIsRevoked, &revoked);
pgpGetSubKeyBoolean (subkey, kPGPKeyPropIsExpired, &expired);
return (revoked || expired);
}
/* Find the default private key. Get the name (or keyid) from the
environment, and find the PGPKey object. If there is no default
key defined in the environment, return NULL unless there is
only one private key in the key database. */
static PGPKey *
pgpGetDefaultPrivateKeyInternal (PGPKeyDB *keyDB)
{
union RingObject *keyobj = NULL, *selectedkey = NULL, *secobj;
struct RingSet *ringset;
struct RingIterator *iter;
PGPKey *key = NULL;
char const *myname = pgpenvGetString
(pgpEnv, PGPENV_MYNAME, NULL, NULL);
ringset = (*keyDB->getRingSet) (keyDB);
iter = ringIterCreate (ringset);
if (!iter)
return NULL;
if (!myname || strlen (myname) == 0) {
/* If only one private key, return that */
while (ringIterNextObject (iter, 1) > 0) {
keyobj = ringIterCurrentObject (iter, 1);
pgpa(pgpaAssert(ringObjectType(keyobj) == RINGTYPE_KEY));
if (ringKeyIsSec (ringset, keyobj) &&
(ringKeyUse (ringset, keyobj) & PGP_PKUSE_SIGN)!=0) {
if (selectedkey) { /* already found one */
selectedkey = NULL;
goto cleanup;
}
else
selectedkey = keyobj; /* found first one */
}
}
}
else {
secobj = ringLatestSecret (ringset, myname, pgpGetTime(), 0);
if (secobj) {
ringIterSeekTo (iter, secobj);
selectedkey = ringIterCurrentObject (iter, 1);
/* Make sure it can sign */
if (!(ringKeyUse (ringset, selectedkey) & PGP_PKUSE_SIGN))
selectedkey = NULL;
}
}
cleanup:
ringIterDestroy (iter);
if (selectedkey) {
key = pgpGetKeyByRingObject (keyDB, selectedkey);
/* Ignore revoked or expired key */
if (key && pgpKeyIsDead (key))
key = NULL;
}
return key;
}
/* END OF INTERNAL FUNCTIONS */
/* Copy an entire key to a new ringset. The newly created ringset is
returned. This function is necessary for two reasons:
1. ringRaiseName requires all names to be present on the ringset to have
any effect.
2. to ensure a complete key (i.e. all it's sub-objects) are copied from
a modified read-only key to a writable keyring.
*/
PGPError
pgpCopyKey (struct RingSet *src, union RingObject *obj, struct RingSet **dest)
{
struct RingIterator *iter = NULL;
int level;
if (!ringSetIsMember (src, obj))
return PGPERR_BADPARAM;
*dest = ringSetCreate (ringSetPool (src));
if (!*dest)
return PGPERR_NOMEM;
iter = ringIterCreate (src);
if (!iter) {
ringSetDestroy (*dest);
return PGPERR_NOMEM;
}
ringIterSeekTo (iter, obj);
ringIterRewind (iter, 2); /* reset iterator to key object */
/* Loop adding objects until next key (level 1), or no more keys
(level 0) */
while ((level = ringIterNextObjectAnywhere (iter)) > 1) {
obj = ringIterCurrentObject (iter, level);
ringSetAddObject (*dest, obj);
}
ringIterDestroy (iter);
return PGPERR_OK;
}
/* Given a key ring object, find the corresponding PGPKey object. */
PGPKey *
pgpGetKeyByRingObject (PGPKeyDB *keyDB, union RingObject *keyobj)
{
PGPKey *keyptr;
pgpAssert (ringObjectType (keyobj) == RINGTYPE_KEY);
for (keyptr = keyDB->firstKeyInDB; keyptr; keyptr = keyptr->nextKeyInDB) {
if (keyobj == keyptr->key)
return keyptr;
}
return NULL;
}
PGPError
pgpRevokeKey (PGPKey *key, char *passphrase)
{
PGPKeyDB *keys = NULL;
struct RingSet *allset = NULL, *addset = NULL;
union RingObject *keyobj;
PGPError error = PGPERR_OK;
pgpa(pgpaPGPKeyValid(key));
keys = key->keyDB;
keyobj = key->key;
if (!(*keys->isMutable) (keys))
return PGPERR_KEYDB_KEYDBREADONLY;
if (pgpKeyIsDead (key))
return PGPERR_OK; /* no need */
allset = pgpKeyDBRingSet (keys);
if (!ringKeyIsSec (allset, keyobj))
return PGPERR_NO_SECKEY; /* not our key */
error = pgpCopyKey (allset, keyobj, &addset);
if (error)
return error;
error = pgpCertifyObject (keyobj, addset, keyobj, allset,
PGP_SIGTYPE_KEY_COMPROMISE, passphrase, FALSE);
if (error) {
ringSetDestroy (addset);
return error;
}
/* Update the KeyDB */
error = pgpAddObjects (keys, addset);
ringSetDestroy (addset);
return error;
}
/* Check whether sufficient entropy exists to generate a key of the
requested type with the requested number of keys. Returns
0 if sufficient entropy exists, or a positive integer representing the
number of bits required. */
unsigned
pgpQueryEntropyNeeded (byte pkalg, unsigned bits)
{
long bits_needed;
Boolean fastgen = pgpenvGetInt (pgpEnv, PGPENV_FASTKEYGEN,
NULL, NULL);
bits_needed = pgpSecKeyEntropy (pgpPkalgByNumber(pkalg), bits, fastgen) -
pgpRandPoolEntropy ();
return (unsigned) ((bits_needed <= 0) ? 0 : bits_needed);
}
/* Return the amount of entropy needed to create a key of the specified
type and size. The application must call pgpRandpoolEntropy() itself
until it has accumulated this much. */
unsigned
pgpKeyEntropyNeeded (byte pkalg, unsigned bits)
{
Boolean fastgen = pgpenvGetInt (pgpEnv, PGPENV_FASTKEYGEN,
NULL, NULL);
return pgpSecKeyEntropy (pgpPkalgByNumber (pkalg), bits, fastgen);
}
/* Allows the caller to add entropy to the random number pool. This will not
normally be called - the app will call Aurora functions directly. */
PGPError
pgpAddRandomBits (byte *random_bits, unsigned num_bytes)
{
pgpRandomAddBytes (pgpRng, random_bits, num_bytes);
return PGPERR_OK;
}
#if 0 /* [ */
static int (*generateYieldProgressFunc)(void *arg, int phase) = NULL;
static void *generateYieldArg = NULL;
static int
generateYieldFunc(void)
{
/* Will this actually work consistently to abort from here? */
if (generateYieldProgressFunc != NULL)
return (*generateYieldProgressFunc)(generateYieldArg, 0);
else
return 0;
}
#endif /* ] */
/* Common code for generating master keys and subkeys. *masterkey
is NULL when generating a master key, and is used to return
the master PGPKey object. If *masterkey contains a value,
a subkey is to be generated associated with the PGPKey object. */
static PGPError
pgpGenerateKeyInternal (PGPKeyDB *keyDB, PGPKey **masterkey,
byte pkalg, unsigned bits,
word16 expiration, char *name, int name_len,
char *passphrase, char *masterpass,
int (*progress) (void *arg, int phase),
void *arg)
{
struct RingSet *allset, *addset = NULL;
union RingObject *newobj = NULL;
PGPError error = PGPERR_OK;
struct PgpSecKey *seckey = NULL, *masterseckey = NULL;
struct PgpKeySpec *keyspec = NULL;
long entropy_needed, entropy_available;
Boolean genMaster = (*masterkey == NULL);
Boolean fastgen = pgpenvGetInt (pgpEnv, PGPENV_FASTKEYGEN,
NULL, NULL);
#if 0 /* [ */
int (*oldBNYield)(void);
generateYieldProgressFunc = progress;
generateYieldArg = arg;
oldBNYield = bnYield;
bnYield = &generateYieldFunc;
#endif /* ] */
/* Check we have sufficient random bits to generate the keypair */
entropy_needed = pgpSecKeyEntropy (pgpPkalgByNumber(pkalg), bits, fastgen);
entropy_available = pgpRandPoolEntropy ();
if (entropy_needed > entropy_available) {
return PGPERR_KEYDB_NEEDMOREBITS;
goto cleanup;
}
/* Generate the secret key */
seckey = pgpSecKeyGenerate(pgpPkalgByNumber(pkalg), bits, fastgen, pgpRng,
progress, arg, &error);
if (error)
goto cleanup;
pgpRandomStir (pgpRng);
/* Need to lock the SecKey with the passphrase. */
if (passphrase && strlen (passphrase) > 0) {
error = pgpSecKeyChangeLock (seckey, pgpEnv, pgpRng,
passphrase, strlen (passphrase));
if (error)
goto cleanup;
}
/* Generate the keyring objects. Use keyspec defaults except for
expiration (validity) period */
keyspec = pgpKeySpecCreate (pgpEnv);
if (!keyspec) {
error = PGPERR_NOMEM;
goto cleanup;
}
pgpKeySpecSetValidity (keyspec, expiration);
allset = pgpKeyDBRingSet (keyDB);
if (genMaster) {
/* Generating master signing key */
addset = ringSetCreate (ringSetPool (allset));
if (!addset) {
error = PGPERR_NOMEM;
goto cleanup;
}
error = ringCreateKeypair (pgpEnv, seckey, keyspec, name, name_len,
pgpRng, addset, addset);
}
else {
/* Generating encryption subkey. Get the master seckey and
unlock it */
error = pgpCopyKey (allset, (*masterkey)->key, &addset);
if (error)
goto cleanup;
masterseckey = ringSecSecKey (allset, (*masterkey)->key,
PGP_PKUSE_SIGN);
if (!masterseckey) {
error = ringSetError(allset)->error;
goto cleanup;
}
if (pgpSecKeyIslocked (masterseckey)) {
if (!passphrase) {
error = PGPERR_KEYDB_BADPASSPHRASE;
goto cleanup;
}
error = pgpSecKeyUnlock (masterseckey, pgpEnv, masterpass,
strlen (masterpass));
if (error != 1) {
if (error == 0)
error = PGPERR_KEYDB_BADPASSPHRASE;
goto cleanup;
}
}
error = ringCreateSubkeypair (pgpEnv, masterseckey, seckey, keyspec,
pgpRng, addset, addset);
}
pgpRandomStir (pgpRng); /* this helps us count randomness in pool */
if (error)
goto cleanup;
/* Add objects to main KeyDB. Before doing so, locate
the master key object and return it. */
ringSetFreeze (addset);
if (genMaster) {
RingIterator *iter = ringIterCreate (addset);
if (!iter) {
error = ringSetError(addset)->error;
goto cleanup;
}
ringIterNextObject (iter, 1);
newobj = ringIterCurrentObject (iter, 1);
ringIterDestroy (iter);
}
error = pgpAddObjects (keyDB, addset);
if (genMaster && !error)
*masterkey = pgpGetKeyByRingObject (keyDB, newobj);
cleanup:
#if 0
bnYield = oldBNYield;
#endif
if (addset)
ringSetDestroy (addset);
if (seckey)
pgpSecKeyDestroy (seckey);
if (masterseckey)
pgpSecKeyDestroy (masterseckey);
if (keyspec)
pgpKeySpecDestroy (keyspec);
return error;
}
/* Generate a new master keypair. The caller must have already generated
sufficient entropy for the keys to be generated. The newly generated
keys are added to the PGPKeyDB referenced by "keyset". */
PGPError
pgpGenerateKey (PGPKeySet *keyset, byte pkalg, unsigned bits,
word16 expiration, char *name, int name_len,
char *passphrase, int (*progress) (void *arg, int phase),
void *arg, PGPKey **key)
{
PGPError error = PGPERR_OK;
PGPKey *newkey = NULL;
pgpa(pgpaPGPKeySetValid(keyset));
if (bits < 512 || bits > 4096 ||
(pkalg != PGP_PKALG_RSA && pkalg != PGP_PKALG_DSA) ||
!name || name_len < 1 || name_len > 256)
return PGPERR_BADPARAM;
*key = NULL;
error = pgpGenerateKeyInternal (keyset->keyDB, &newkey, pkalg, bits,
expiration, name, name_len, passphrase,
NULL, progress, arg);
if (!error && key)
*key = newkey;
return error;
}
/* Generate a subkey pair. The passphrase is that of the master
key. Note that the subkey is protected by the same passphrase
as its master. */
PGPError
pgpGenerateSubKey (PGPKey *masterkey, unsigned bits,
word16 expiration, char *passphrase, char *masterpass,
int (*progress) (void *arg, int phase), void *arg)
{
long pkalg = 0;
pgpa(pgpaPGPKeyValid(masterkey));
if (bits < 512 || bits > 4096)
return PGPERR_BADPARAM;
if (pgpKeyIsDead (masterkey))
return PGPERR_BADPARAM;
pgpGetKeyNumber (masterkey, kPGPKeyPropAlgId, &pkalg);
if (pkalg != PGP_PKALG_DSA)
return PGPERR_BADPARAM;
return pgpGenerateKeyInternal (masterkey->keyDB, &masterkey,
PGP_PKALG_ELGAMAL, bits,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -