📄 pgpkeyman.c
字号:
/*____________________________________________________________________________
Copyright (C) 1997 Network Associates Inc. and affiliated companies.
All rights reserved.
$Id: pgpKeyMan.c,v 1.208 1999/05/17 05:08:11 hal Exp $
____________________________________________________________________________*/
#include <string.h>
#include "pgpConfig.h"
#include "pgpContext.h"
#include "pgpEncodePriv.h"
#include "pgpEventPriv.h"
#include "pgpKDBInt.h"
#include "pgpDebug.h"
#include "pgpRngPub.h"
#include "pgpRngRead.h"
#include "pgpPubKey.h"
#include "pgpRandomX9_17.h"
#include "pgpRandomPool.h"
#include "pgpSigSpec.h"
#include "pgpStr2Key.h"
#include "pgpKeySpec.h"
#include "pgpTrstPkt.h"
#include "pgpTrust.h"
#include "pgpHash.h"
#include "pgpEnv.h"
#include "pgpSDKPrefs.h"
#include "bn.h"
#include "pgpRegExp.h"
#include "pgpRngPub.h"
#include "pgpRngMnt.h"
#include "pgpTimeDate.h"
#include "pgpKeyIDPriv.h"
#include "pgpUtilitiesPriv.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpX509Priv.h"
#define MAXRSABITS 2048
#define elemsof(x) ((unsigned)(sizeof(x)/sizeof(*x)))
/* 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. */
#define SIG_EXPORTABLE TRUE
#define SIG_NON_EXPORTABLE FALSE
#define SIG_EXPORTABLEHASHED TRUE
#define SIG_EXPORTABLEUNHASHED FALSE
static PGPError
pgpCertifyObject(
PGPContextRef context,
union RingObject *to_sign,
RingSet *dest,
union RingObject *signer,
RingSet const *src,
PGPByte sigtype,
char const *passphrase,
PGPSize passphraseLength,
PGPBoolean hashedPhrase,
PGPBoolean selfsig,
PGPBoolean exportable,
PGPBoolean exportableHashed,
PGPTime sigCreation,
PGPUInt32 sigExpiration,
PGPByte trustDepth,
PGPByte trustValue,
char const *sRegExp,
RingSet const *rakset,
PGPUInt32 rakclass
)
{
PGPSecKey *seckey = NULL;
PGPSigSpec *sigspec = NULL;
PGPEnv *pgpEnv;
PGPRandomContext *pgpRng;
RingIterator *rakIter;
PGPError error = kPGPError_NoErr;
pgpEnv = pgpContextGetEnvironment( context );
pgpRng = pgpContextGetX9_17RandomContext( context );
/* Error if not enough entropy for a safe signature */
if( ! PGPGlobalRandomPoolHasMinimumEntropy() )
return kPGPError_OutOfEntropy;
if (IsntNull(passphrase) && passphraseLength == 0)
passphrase = NULL;
if (!signer || !ringKeyIsSec (src, signer) ||
!(ringKeyUse (src, signer) & PGP_PKUSE_SIGN))
return kPGPError_SecretKeyNotFound;
seckey = ringSecSecKey (src, signer, PGP_PKUSE_SIGN);
if (!seckey)
return ringSetError(src)->error;
if (pgpSecKeyIslocked (seckey)) {
if (IsNull( passphrase )) {
pgpSecKeyDestroy (seckey);
return kPGPError_BadPassphrase;
}
error = (PGPError)pgpSecKeyUnlock (seckey, pgpEnv, passphrase,
passphraseLength, hashedPhrase);
if (error != 1)
{
pgpSecKeyDestroy (seckey);
if (error == 0)
error = kPGPError_BadPassphrase;
return error;
}
}
sigspec = pgpSigSpecCreate (pgpEnv, seckey, sigtype);
if (!sigspec) {
pgpSecKeyDestroy (seckey);
return kPGPError_OutOfMemory;
}
if (seckey->pkAlg > kPGPPublicKeyAlgorithm_RSA + 2 &&
sigtype == PGP_SIGTYPE_KEY_GENERIC && selfsig) {
/* Propagate sig subpacket information */
PGPByte const *p;
PGPSize plen;
pgpSigSpecSetVersion (sigspec, PGPVERSION_4);
if ((p=ringKeyFindSubpacket (signer, src,
SIGSUB_PREFERRED_ENCRYPTION_ALGS, 0,
&plen, NULL, NULL, NULL, NULL, NULL)) != 0) {
pgpSigSpecSetPrefAlgs (sigspec, 0, p, plen);
}
if (ringKeyExpiration (src, signer)) {
PGPUInt32 period = ringKeyExpiration (src, signer) -
ringKeyCreation (src, signer);
pgpSigSpecSetKeyExpiration (sigspec, 0, period);
}
}
if (!exportable) {
pgpSigSpecSetExportable (sigspec,
(exportableHashed ? 0 : kPGPSigFlags_Unhashed),
exportable);
}
if( sigCreation != 0 )
{
pgpSigSpecSetTimestamp( sigspec, sigCreation +
(60 * 60 * pgpenvGetInt(pgpEnv, PGPENV_TZFIX, NULL, NULL)));
}
if (sigExpiration)
pgpSigSpecSetSigExpiration (sigspec, 0, sigExpiration);
if( IsntNull( sRegExp ) )
pgpSigSpecSetRegExp (sigspec, 0, sRegExp);
/* Ignore trustValue for ordinary level 0 signatures */
if (trustDepth != 0) {
/* Convert trust value to extern format */
if (trustValue != 0)
trustValue = ringTrustOldToExtern(ringSetPool(dest), trustValue);
/* Note that setting nonzero trustvalue forces V4 sigs */
pgpSigSpecSetTrustLevel (sigspec, 0, trustDepth, trustValue);
}
pgpRng = pgpContextGetX9_17RandomContext( context );
/* Due to a bug in 5.0, all sigs directly on keys must be version 2_6.
* However the only signatures 5.0 handles directly on keys are key
* revocations.
*/
if (ringObjectType( to_sign ) == RINGTYPE_KEY &&
!ringKeyIsSubkey( dest, to_sign ) &&
sigtype == PGP_SIGTYPE_KEY_REVOKE ) {
pgpSigSpecSetVersion( sigspec, PGPVERSION_3 );
}
/* Handle revocation authorizations */
if( IsntNull( rakset ) ) {
rakIter = ringIterCreate (rakset);
if (!rakIter) {
pgpSecKeyDestroy (seckey);
pgpSigSpecDestroy (sigspec);
return ringSetError(rakset)->error;
}
while (ringIterNextObject (rakIter, 1) > 0) {
PGPByte krinfo[22];
PGPByte pkalg;
RingObject *krkey = ringIterCurrentObject (rakIter, 1);
/* Note that rakclass must have 0x80 set to be effective */
ringKeyID8 (rakset, krkey, &pkalg, NULL);
krinfo[0] = rakclass;
krinfo[1] = pkalg;
ringKeyFingerprint20 (rakset, krkey, krinfo+2);
error = pgpSigSpecSetRevocationKey (sigspec, 0, krinfo,
sizeof(krinfo) );
if (IsPGPError(error)) {
pgpSecKeyDestroy (seckey);
pgpSigSpecDestroy (sigspec);
ringIterDestroy (rakIter);
return error;
}
}
ringIterDestroy (rakIter);
/* Make this signature non-revocable */
pgpSigSpecSetRevocable (sigspec, 0, FALSE);
}
/* Do the signature at the Aurora level */
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 PGPError
pgpKeyDeadCheck( PGPKeyRef key)
{
PGPBoolean revoked, expired;
PGPError err;
err = PGPGetKeyBoolean (key, kPGPKeyPropIsRevoked, &revoked);
if ( IsntPGPError( err ) && revoked )
err = kPGPError_KeyRevoked;
if ( IsntPGPError( err ) )
{
err = PGPGetKeyBoolean (key, kPGPKeyPropIsExpired, &expired);
if ( IsntPGPError( err ) && expired )
err = kPGPError_KeyExpired;
}
return ( err );
}
/* Same for subkey... */
static PGPBoolean
pgpSubKeyIsDead (PGPSubKeyRef subkey)
{
PGPBoolean 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.
The refCount on the key is incremented by this routine.
*/
static PGPError
pgpGetDefaultPrivateKeyInternal(
PGPKeyDBRef keyDB,
PGPKey ** outKey)
{
PGPError err = kPGPError_NoErr;
PGPByte * keyIDData = NULL;
void * vkeyIDData;
PGPSize keyIDSize = 0;
PGPContextRef context = pgpGetKeyDBContext( keyDB );
PGPValidatePtr( outKey );
*outKey = kInvalidPGPKeyRef;
err = PGPsdkPrefGetData( context, kPGPsdkPref_DefaultKeyID,
&vkeyIDData, &keyIDSize );
keyIDData = vkeyIDData;
if ( IsntPGPError( err ) )
{
PGPKeyID keyID;
err = PGPImportKeyID( keyIDData, &keyID );
if ( IsntPGPError( err ) )
{
PGPKeySetRef kset = pgpKeyDBRootSet( keyDB );
err = PGPGetKeyByKeyID( kset, &keyID,
kPGPPublicKeyAlgorithm_Invalid, outKey );
PGPFreeKeySet( kset );
}
/* we used public API call; must free using PGPFreeData() */
PGPFreeData( keyIDData );
}
return err;
}
/* 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 (RingSet const *src, union RingObject *obj, RingSet **dest)
{
RingIterator *iter = NULL;
int level;
if (!ringSetIsMember (src, obj))
return kPGPError_BadParams;
*dest = ringSetCreate (ringSetPool (src));
if (!*dest)
return kPGPError_OutOfMemory;
iter = ringIterCreate (src);
if (!iter) {
ringSetDestroy (*dest);
return kPGPError_OutOfMemory;
}
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 kPGPError_NoErr;
}
/* Given a key ring object, find the corresponding PGPKey object. */
PGPKey *
pgpGetKeyByRingObject (PGPKeyDBRef keyDB, union RingObject *keyobj)
{
PGPKeyRef keyptr;
pgpAssert (ringObjectType (keyobj) == RINGTYPE_KEY);
for (keyptr = keyDB->firstKeyInDB; keyptr; keyptr = keyptr->nextKeyInDB) {
if (keyobj == keyptr->key)
return keyptr;
}
return NULL;
}
static PGPError
sRevokeKey (
PGPContextRef context,
PGPKeyRef key,
char const * passphrase,
PGPSize passphraseLength,
PGPBoolean hashedPhrase
)
{
PGPKeyDBRef keys = NULL;
RingSet const * allset = NULL;
RingSet * addset = NULL;
union RingObject *keyobj;
union RingObject *signkeyobj = NULL;
PGPUInt32 revnum;
PGPError error = kPGPError_NoErr;
keys = key->keyDB;
keyobj = key->key;
if ( !keys->objIsMutable( keys, keyobj ) )
return kPGPError_ItemIsReadOnly;
if ( IsPGPError( pgpKeyDeadCheck(key) ) )
return kPGPError_NoErr; /* no need */
allset = pgpKeyDBRingSet (keys);
error = pgpCopyKey (allset, keyobj, &addset);
if (error)
return error;
revnum = 0;
for ( ; ; ) {
signkeyobj = keyobj;
/* See if we have an authorized revocation signature */
if (!ringKeyIsSec (allset, keyobj)) {
PGPByte revclass;
signkeyobj = ringKeyRevocationKey (keyobj, allset, revnum++,
NULL, NULL,
&revclass, NULL, &error);
if( IsPGPError( error ) ) {
if( error == kPGPError_ItemNotFound )
error = kPGPError_NoErr;
break;
}
if( IsNull( signkeyobj ) )
continue;
if (!(revclass & 0x80))
continue;
if (!ringKeyIsSec (allset, signkeyobj))
continue;
}
error = pgpCertifyObject (context, keyobj, addset, signkeyobj, allset,
PGP_SIGTYPE_KEY_REVOKE, passphrase,
passphraseLength, hashedPhrase, FALSE,
SIG_EXPORTABLE, 0, 0, kPGPExpirationTime_Never,
0, 0, NULL, NULL, 0);
/* Retry if bad passphrase and we are an authorized revoker */
if (error != kPGPError_BadPassphrase || signkeyobj == keyobj)
break;
}
if (error) {
ringSetDestroy (addset);
return error;
}
/* Update the KeyDB */
error = pgpAddObjects (keys, addset);
ringSetDestroy (addset);
/* Calculate trust changes as a result */
if( error == kPGPError_NoErr )
(void)pgpPropagateTrustKeyDB (keys);
return error;
}
static const PGPOptionType revkeyOptionSet[] = {
kPGPOptionType_Passphrase,
kPGPOptionType_Passkey
};
PGPError
pgpRevokeKeyInternal(
PGPKeyRef key,
PGPOptionListRef optionList )
{
PGPContextRef context;
char * passphrase;
PGPSize passphraseLength;
PGPBoolean hashedPhrase = FALSE;
PGPError err = kPGPError_NoErr;
pgpa(pgpaPGPKeyValid(key));
PGPValidateKey( key );
context = key->keyDB->context;
if (IsPGPError( err = pgpCheckOptionsInSet( optionList,
revkeyOptionSet, elemsof( revkeyOptionSet ) ) ) )
return err;
/* Pick up optional options */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_Passphrase, FALSE,
"%p%l", &passphrase, &passphraseLength ) ) )
goto error;
if (IsNull( passphrase )) {
hashedPhrase = TRUE;
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_Passkey, FALSE,
"%p%l", &passphrase, &passphraseLength ) ) )
goto error;
}
err = sRevokeKey( context, key, passphrase, passphraseLength,
hashedPhrase );
error:
return err;
}
static const PGPOptionType keyentOptionSet[] = {
kPGPOptionType_KeyGenParams,
kPGPOptionType_KeyGenFast,
kPGPOptionType_KeyGenUseExistingEntropy
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -