📄 pgpkeyman.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
$Id: pgpKeyMan.c,v 1.141 2002/10/29 04:50:59 ajivsov Exp $
____________________________________________________________________________*/
#include <string.h>
#include "pgpConfig.h"
#include "pgpSDKPriv.h" /* DO NOT REMOVE */
#include "pgpContext.h"
#include "pgpEncodePriv.h"
#include "pgpEventPriv.h"
#include "pgpDebug.h"
#include "pgpKeyPriv.h"
#include "pgpPubKey.h"
#include "pgpRandomX9_17.h"
#include "pgpRandomPool.h"
#include "pgpSigSpec.h"
#include "pgpStr2Key.h"
#include "pgpKeySpec.h"
#include "pgpHash.h"
#include "pgpEnv.h"
#include "pgpP11Key.h"
#include "pgpTokenLib.h"
#include "pgpRegExp.h"
#include "pgpTimeDate.h"
#include "pgpTrustPriv.h"
#include "pgpUtilitiesPriv.h"
#include "pgpRandomPoolPriv.h"
#include "pgpRnd.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpX509Priv.h"
#include "pgpPassCach.h"
#define MAXRSABITS 4096
#define elemsof(x) ((unsigned)(sizeof(x)/sizeof(*x)))
/* INTERNAL FUNCTIONS */
/*
* Internal functions for certifying a key or userid.
*
* Sigspec holds the information about the kind of signature to make.
* It is automatically freed after the sig itself is created, or if there
* is an error in trying to modify it.
*/
#define SIG_EXPORTABLE TRUE
#define SIG_NON_EXPORTABLE FALSE
#define SIG_EXPORTABLEHASHED TRUE
#define SIG_EXPORTABLEUNHASHED FALSE
extern PGPMutex_t sRpcMutex;
static PGPError
sCreateSigSpec(
PGPContextRef context,
PGPKeyDBObj *signer,
PGPByte sigtype,
char const *passphrase,
PGPSize passphraseLength,
PGPBoolean hashedPhrase,
PGPUInt32 cacheTimeOut,
PGPBoolean cacheGlobal,
PGPSigSpec **psigspec)
{
PGPSigSpec *sigspec = NULL;
PGPEnv *pgpEnv;
PGPError error = kPGPError_NoErr;
pgpEnv = pgpContextGetEnvironment( context );
/* Error if not enough entropy for a safe signature */
if( ! PGPGlobalRandomPoolHasMinimumEntropy() )
return kPGPError_OutOfEntropy;
if (IsntNull(passphrase) && passphraseLength == 0)
passphrase = NULL;
if (!signer || !pgpKeyIsSec (signer) ||
!(pgpKeyUse (signer) & PGP_PKUSE_SIGN))
return kPGPError_SecretKeyNotFound;
if( !pgpSecPassphraseOK( signer, (PGPByte *) passphrase,
passphraseLength, hashedPhrase, cacheTimeOut,
cacheGlobal ) )
return kPGPError_BadPassphrase;
sigspec = pgpSigSpecCreate (pgpEnv, signer, sigtype);
if (!sigspec)
return kPGPError_OutOfMemory;
pgpSigSpecSetPassphrase( sigspec, (PGPByte *) passphrase,
passphraseLength, hashedPhrase );
*psigspec = sigspec;
return error;
}
static PGPError
sSigSpecAddRAK(
PGPSigSpec *sigspec,
PGPKeySet *rakset,
PGPUInt32 rakclass)
{
PGPKeyDBObj *krkey;
PGPKeyIter *rakIter;
PGPError err = kPGPError_NoErr;
/* Handle revocation authorizations */
pgpAssert( IsntNull( rakset ) );
err = PGPNewKeyIterFromKeySet( rakset, &rakIter );
if (IsPGPError( err )) {
pgpSigSpecDestroy (sigspec);
return err;
}
while( IsntPGPError( PGPKeyIterNextKeyDBObj( rakIter,
kPGPKeyDBObjType_Key, &krkey ) ) ) {
PGPByte krinfo[22];
PGPByte pkalg;
/* Note that rakclass must have 0x80 set to be effective */
pgpKeyID8 (krkey, &pkalg, NULL);
krinfo[0] = rakclass;
krinfo[1] = pkalg;
pgpKeyFingerprint20 (krkey, krinfo+2);
err = pgpSigSpecSetRevocationKey (sigspec, 0, krinfo,
sizeof(krinfo) );
if (IsPGPError(err)) {
pgpSigSpecDestroy (sigspec);
PGPFreeKeyIter (rakIter);
return err;
}
}
PGPFreeKeyIter (rakIter);
/* Make this signature non-revocable */
pgpSigSpecSetRevocable (sigspec, 0, FALSE);
return kPGPError_NoErr;
}
static PGPError
sSigSpecSetExportability(
PGPSigSpec *sigspec,
PGPBoolean exportable,
PGPBoolean exportableHashed)
{
if (!exportable) {
pgpSigSpecSetExportable (sigspec,
(exportableHashed ? 0 : kPGPSigFlags_Unhashed),
exportable);
}
return kPGPError_NoErr;
}
static PGPError
sSigSpecSetTimes(
PGPSigSpec *sigspec,
PGPTime sigCreation,
PGPUInt32 sigExpiration)
{
PGPContextRef context;
PGPEnv *pgpEnv;
context = pgpSigSpecContext( sigspec );
pgpEnv = pgpContextGetEnvironment( context );
if( sigCreation != 0 )
pgpSigSpecSetTimestamp( sigspec, sigCreation +
(60 * 60 * pgpenvGetInt(pgpEnv, PGPENV_TZFIX, NULL, NULL)));
if (sigExpiration)
pgpSigSpecSetSigExpiration (sigspec, 0, sigExpiration);
return kPGPError_NoErr;
}
static PGPError
sSigSpecSetTrustParams(
PGPSigSpec *sigspec,
PGPKeyDB *kdb,
PGPByte trustDepth,
PGPByte trustValue,
char const *sRegExp)
{
PGPEnv *pgpEnv;
PGPContextRef context;
if( IsntNull( sRegExp ) )
pgpSigSpecSetRegExp (sigspec, 0, sRegExp);
context = PGPPeekKeyDBContext( kdb );
pgpEnv = pgpContextGetEnvironment( context );
/* Ignore trustValue for ordinary level 0 signatures */
if (trustDepth != 0) {
/* Convert trust value to extern format */
if (trustValue != 0)
trustValue = pgpTrustOldToExtern(pgpEnv, trustValue);
/* Note that setting nonzero trustvalue forces V4 sigs */
pgpSigSpecSetTrustLevel (sigspec, 0, trustDepth, trustValue);
}
return kPGPError_NoErr;
}
/* Create the certification based on info in sigspec */
static PGPError
sCertifyObject(
PGPSigSpec *sigspec,
PGPKeyDBObj *signee)
{
PGPContextRef context;
PGPBoolean selfsig = FALSE;
PGPKeyDBObj * parent;
PGPKeyDBObj * signer;
PGPByte sigtype;
PGPInt32 pkalg;
PGPError error = kPGPError_NoErr;
context = pgpSigSpecContext( sigspec );
sigtype = pgpSigSpecSigType( sigspec );
signer = pgpSigSpecSeckey( sigspec );
pgpGetKeyNumber( signer, kPGPKeyProperty_AlgorithmID, &pkalg );
parent = PGPPeekKeyDBObjKey( signee );
if( parent == signer )
selfsig = TRUE;
if (pkalg > kPGPPublicKeyAlgorithm_RSA &&
sigtype == PGP_SIGTYPE_KEY_GENERIC && selfsig) {
/* Propagate sig subpacket information */
PGPByte const *p;
PGPSize plen;
PGPBoolean hashed;
PGPError dumerr;
pgpSigSpecSetVersion (sigspec, PGPVERSION_4);
if ((p=pgpKeyFindSubpacket (signer,
SIGSUB_PREFERRED_ENCRYPTION_ALGS, 0,
&plen, NULL, &hashed, NULL, NULL, &dumerr)) != 0
&& hashed) {
pgpSigSpecSetPrefAlgs (sigspec, 0, p, plen);
}
if (pgpKeyExpiration (signer)) {
PGPUInt32 period = pgpKeyExpiration (signer) -
pgpKeyCreation (signer);
pgpSigSpecSetKeyExpiration (sigspec, 0, period);
}
}
/* 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 (pgpObjectType( signee ) == RINGTYPE_KEY &&
!pgpKeyIsSubkey( signee ) &&
sigtype == PGP_SIGTYPE_KEY_REVOKE ) {
pgpSigSpecSetVersion( sigspec, PGPVERSION_3 );
}
/* Perform the signature calculation */
error = pgpSignObject (signee, sigspec);
pgpKeyDBChanged( PGPPeekKeyDBObjKeyDB(signee), TRUE );
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( PGPKeyDBObjRef key)
{
PGPBoolean revoked, expired;
PGPError err;
err = pgpGetKeyBoolean (key, kPGPKeyProperty_IsRevoked, &revoked);
if ( IsntPGPError( err ) && revoked )
err = kPGPError_KeyRevoked;
if ( IsntPGPError( err ) )
{
err = pgpGetKeyBoolean (key, kPGPKeyProperty_IsExpired, &expired);
if ( IsntPGPError( err ) && expired )
err = kPGPError_KeyExpired;
}
return ( err );
}
/* Same for subkey... */
static PGPBoolean
pgpSubKeyIsDead (PGPKeyDBObjRef subkey)
{
PGPBoolean revoked, expired;
pgpGetSubKeyBoolean (subkey, kPGPSubKeyProperty_IsRevoked, &revoked);
pgpGetSubKeyBoolean (subkey, kPGPSubKeyProperty_IsExpired, &expired);
return (revoked || expired);
}
#if 0
/* Find the default private key. Get the name (or keyid) from the
environment, and find the PGPKeyDBObj. If there is no default
key defined in the environment, return NULL unless there is
only one private key in the key database.
*/
static PGPError
pgpGetDefaultPrivateKeyInternal(
PGPKeyDBRef keyDB,
PGPKeyDBObj ** outKey)
{
PGPError err = kPGPError_NoErr;
PGPByte * keyIDData = NULL;
void * vkeyIDData;
PGPSize keyIDSize = 0;
PGPContextRef context = PGPPeekKeyDBContext( keyDB );
PGPValidatePtr( outKey );
*outKey = kInvalidPGPKeyDBObjRef;
err = PGPsdkPrefGetData( context, kPGPsdkPref_DefaultKeyID,
&vkeyIDData, &keyIDSize );
keyIDData = vkeyIDData;
if ( IsntPGPError( err ) )
{
PGPKeyID keyID;
err = PGPImportKeyID( keyIDData, &keyID );
if ( IsntPGPError( err ) )
{
err = PGPGetKeyByKeyID( keyDB, &keyID,
kPGPPublicKeyAlgorithm_Invalid, outKey );
}
/* we used public API call; must free using PGPFreeData() */
PGPFreeData( keyIDData );
}
return err;
}
#endif
static PGPInt32
sGetKeyTokenNum( PGPKeyDBObj *key )
{
PGPKeyInfo *kinfo;
if( !pgpKeyIsOnToken(key) )
return -1;
pgpAssert(OBJISKEY(key));
kinfo = pgpKeyToKeyInfo( key );
return kinfo->tokenNum1 - 1;
}
/* END OF INTERNAL FUNCTIONS */
/* This is also called on the backend for revoking subkeys */
PGPError
pgpRevokeKey_internal (
PGPKeyDBObjRef key,
char const * passphrase,
PGPSize passphraseLength,
PGPBoolean hashedPhrase,
PGPUInt32 cacheTimeOut,
PGPBoolean cacheGlobal
)
{
PGPKeyDBRef keys = NULL;
PGPContextRef context;
PGPKeyDBObj *signkey = NULL;
PGPUInt32 revnum = 0;
PGPSigSpec * sigspec;
PGPError error = kPGPError_NoErr;
if( pgpObjectType( key ) == RINGTYPE_SUBKEY )
return pgpRevokeSubKey_internal( key, passphrase, passphraseLength,
hashedPhrase, cacheTimeOut, cacheGlobal );
keys = PGPPeekKeyDBObjKeyDB( key );
context = PGPPeekKeyDBContext( keys );
if ( IsPGPError( pgpKeyDeadCheck(key) ) )
return kPGPError_NoErr; /* no need */
for ( ; ; ) {
signkey = key;
/* See if we have an authorized revocation signature */
if (!pgpKeyIsSec (key)) {
PGPByte revclass;
signkey = pgpKeyRevocationKey (key, revnum++, NULL, NULL,
&revclass, NULL, &error);
if( IsPGPError( error ) ) {
if( error == kPGPError_ItemNotFound )
error = kPGPError_NoErr;
break;
}
if( IsNull( signkey ) )
continue;
if (!(revclass & 0x80))
continue;
if (!pgpKeyIsSec (signkey))
continue;
}
error = sCreateSigSpec( context, signkey, PGP_SIGTYPE_KEY_REVOKE,
passphrase, passphraseLength, hashedPhrase,
cacheTimeOut, cacheGlobal, &sigspec );
if( IsntPGPError( error ) )
error = sCertifyObject( sigspec, key );
/* Retry if bad passphrase and we are an authorized revoker */
if (error != kPGPError_BadPassphrase || signkey == key)
break;
}
return error;
}
static const PGPOptionType revkeyOptionSet[] = {
kPGPOptionType_Passphrase,
kPGPOptionType_Passkey,
kPGPOptionType_CachePassphrase
};
PGPError
pgpRevokeKeyInternal(
PGPKeyDBObjRef key,
PGPOptionListRef optionList )
{
char * passphrase;
PGPSize passphraseLength;
PGPBoolean hashedPhrase = FALSE;
PGPUInt32 cacheTimeOut = 0;
PGPBoolean cacheGlobal;
PGPError err = kPGPError_NoErr;
pgpa(pgpaPGPKeyValid(key));
PGPValidateKey( key );
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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -