📄 pgpkeylib.c
字号:
/*
* pgpKeyLib.c
* Initialization and cleanup functions related to the keydb library
*
* Copyright (C) 1996,1997 Network Associates Inc. and affiliated companies.
* All rights reserved
*
* $Id: pgpKeyLib.c,v 1.134.2.1 1999/06/11 00:30:38 heller Exp $
*/
#include "pgpConfig.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "pgpContext.h"
#include "pgpKeyDB.h"
#include "pgpDebug.h"
#include "pgpKDBInt.h"
#include "pgpEncodePriv.h"
#include "pgpEnv.h"
#include "pgpErrors.h"
#include "pgpFileNames.h"
#include "pgpFileRef.h"
#include "pgpFileSpec.h"
#include "pgpPipeline.h"
#include "pgpRandomX9_17.h"
#include "pgpRandomPoolPriv.h"
#include "pgpRndSeed.h"
#include "pgpRngRead.h"
#include "pgpSigSpec.h"
#include "pgpTimeDate.h"
#include "pgpTrstPkt.h"
#include "pgpSDKPrefs.h"
#include "pgpOptionList.h"
#include "pgpUtilitiesPriv.h"
#include "pgpX509Priv.h"
#if PGP_MACINTOSH
#include "MacStrings.h"
#include "MacFiles.h"
#endif
#include "pgpDEBUGStartup.h"
#define elemsof(x) ((unsigned)(sizeof(x)/sizeof(*x)))
/* See if the newly opened keyring appears to needs sig checking */
static PGPError
sIsSigCheckNeeded( PGPKeySetRef set, PGPBoolean *sigCheckNeeded )
{
RingSet const * rset;
RingIterator * riter;
int level;
PGPBoolean needSigCheck;
*sigCheckNeeded = FALSE;
needSigCheck = FALSE;
rset = pgpKeyDBRingSet( set->keyDB );
riter = ringIterCreate( rset );
if ( !riter )
return ringSetError( rset )->error;
/*
* We look for a key with a revocation signature which has not
* been tried, such that the key's revoke bit is not set. This is
* how some old version of PGP leave revocations. We always set the
* key's revocation bit in the file, so this will not happen with
* keyrings written by this library.
*/
while ( (level = ringIterNextObjectAnywhere( riter ) ) > 0 )
{
if ( level == 2 )
{
RingObject *obj = ringIterCurrentObject( riter, level );
if ( ringObjectType( obj ) == RINGTYPE_SIG &&
ringSigType( rset, obj ) == PGP_SIGTYPE_KEY_REVOKE &&
ringSigTrust( rset, obj ) == PGP_SIGTRUST_UNTRIED )
{
RingObject *parent = ringIterCurrentObject( riter, level - 1 );
if ( ringObjectType( parent ) == RINGTYPE_KEY &&
!ringKeyRevoked( rset, parent ) )
{
/* Here we have our case we are looking for */
needSigCheck = TRUE;
break;
}
}
}
}
ringIterDestroy( riter );
*sigCheckNeeded = needSigCheck;
return kPGPError_NoErr;
}
static PGPError
pgpGetDefaultRingFileRefs(
PGPContextRef cdkContext,
PFLFileSpecRef *pubRefOut,
PFLFileSpecRef *privRefOut )
{
PGPError err = kPGPError_NoErr;
/* set outputs to default */
if ( IsntNull( privRefOut ) )
*privRefOut = NULL;
if ( IsntNull( pubRefOut ) )
*pubRefOut = NULL;
/* load preferences if not already loaded */
if ( IsNull( pgpContextGetPrefs( cdkContext ) ) )
{
err = PGPsdkLoadDefaultPrefs( cdkContext );
}
if ( IsntPGPError( err ) )
{
if ( IsntNull( privRefOut ) )
{
err = PGPsdkPrefGetFileSpec( cdkContext,
kPGPsdkPref_PrivateKeyring, (PGPFileSpecRef *)privRefOut);
}
if ( IsntPGPError( err ) && IsntNull( pubRefOut ) )
{
err = PGPsdkPrefGetFileSpec( cdkContext,
kPGPsdkPref_PublicKeyring, (PGPFileSpecRef *)pubRefOut);
if ( IsPGPError( err ) )
{
PFLFreeFileSpec( *privRefOut );
*privRefOut = NULL;
}
}
}
return err;
}
/*
* Open default keyrings for user, return keyset for it.
* If isMutable is false, keyrings are read only.
*/
PGPError
PGPOpenDefaultKeyRings(
PGPContextRef cdkContext,
PGPKeyRingOpenFlags openFlags,
PGPKeySetRef * keySetOut )
{
PFLFileSpecRef secFileRef = NULL; /* File reference for secret keyring */
PFLFileSpecRef pubFileRef = NULL; /* File reference for public keyring */
PGPError err = kPGPError_NoErr;
PGPKeySetRef set = NULL;
PGPValidatePtr( keySetOut );
*keySetOut = NULL;
PGPValidateContext( cdkContext );
err = pgpGetDefaultRingFileRefs( cdkContext, &pubFileRef, &secFileRef);
if ( IsntPGPError( err ) )
{
pgpAssert( IsntNull( pubFileRef ) );
pgpAssert( IsntNull( secFileRef ) );
err = PGPOpenKeyRingPair(cdkContext, openFlags,
(PGPFileSpecRef)pubFileRef,
(PGPFileSpecRef)secFileRef, &set);
PFLFreeFileSpec( secFileRef );
PFLFreeFileSpec( pubFileRef );
}
if ( IsPGPError( err ) && IsntNull( set ) )
{
PGPFreeKeySet( set );
set = NULL;
}
*keySetOut = set;
pgpAssertErrWithPtr( err, *keySetOut );
return err;
}
/*
* Open the specified keyrings for user, return keyset for it.
* If isMutable is false, keyrings are read only.
*/
PGPError
PGPOpenKeyRingPair(
PGPContextRef cdkContext,
PGPKeyRingOpenFlags openFlags,
PGPFileSpecRef pubFileRefIn,
PGPFileSpecRef privFileRefIn,
PGPKeySetRef * keySetOut )
{
PGPKeyDB *dbsec = NULL, /* KeyDB for secret keyring */
*dbpub = NULL, /* KeyDB for public keyring */
*dbunion = NULL; /* KeyDB for union of both keyrings */
RingPool *pgpRingPool; /* RingPool from cdkContext */
PGPKeySet *set = NULL;
PGPBoolean sigCheckNeeded;
PGPError err;
PFLFileSpecRef pubFileRef = (PFLFileSpecRef)pubFileRefIn;
PFLFileSpecRef privFileRef = (PFLFileSpecRef)privFileRefIn;
PFLFileInfo pubFileInfo;
PGPTime curTime, pubModTime;
PGPValidatePtr( keySetOut );
*keySetOut = NULL;
PGPValidateContext( cdkContext );
PFLValidateFileSpec( pubFileRef );
PFLValidateFileSpec( privFileRef );
pgpAssert( (openFlags & kPGPKeyRingOpenFlags_Reserved) == 0 );
pgpAssert(0 == (openFlags & (kPGPKeyRingOpenFlags_Private |
kPGPKeyRingOpenFlags_Trusted)));
pgpRingPool = pgpContextGetRingPool( cdkContext );
/*
* Check creation time of pub file so we can check for objects
* expired since then.
*/
err = PFLGetFileInfo( pubFileRef, &pubFileInfo );
if( IsPGPError( err ) )
{
err = kPGPError_NoErr;
pubModTime = 0UL;
} else {
pubModTime = PGPGetPGPTimeFromStdTime( pubFileInfo.modificationTime );
}
/* Create key databases for these files. Don't bother with keypool.
Private keyring is not trusted (no trust packets) */
if ((dbsec = pgpCreateFileKeyDB(cdkContext, privFileRef,
(PGPKeyRingOpenFlags)
(openFlags | kPGPKeyRingOpenFlags_Private),
pgpRingPool, &err)) == NULL)
goto error;
if ((dbpub = pgpCreateFileKeyDB(cdkContext, pubFileRef,
(PGPKeyRingOpenFlags)
(openFlags | kPGPKeyRingOpenFlags_Trusted),
pgpRingPool, &err)) == NULL)
goto error;
/* Create union database for these two files */
if ((dbunion = pgpCreateUnionKeyDB(cdkContext, &err)) == NULL)
goto error;
err = pgpUnionKeyDBAdd(dbunion, dbsec);
if ( IsPGPError( err ) )
goto error;
dbsec = NULL; /* dbunion now has responsibility for freeing dbsec */
err = pgpUnionKeyDBAdd(dbunion, dbpub);
if ( IsPGPError( err ) )
goto error;
dbpub = NULL; /* dbunion now has responsibility for freeing dbpub */
/*
* Verify that we have sufficient ringsets to work with union.
* It is easier to check for this now than to check everywhere we
* ask for a ringset.
*/
if (dbunion->getRingSet(dbunion) == NULL) {
/* Insufficient ringsets */
err = kPGPError_OutOfRings;
goto error;
}
err = pgpBuildKeyPool(dbunion, 0);
if ( IsPGPError( err ) )
goto error;
set = pgpKeyDBRootSet(dbunion);
if ( IsNull( set ) )
{
err = kPGPError_OutOfMemory; /* XXX Improve error */
goto error;
}
/*
* Some earlier versions of PGP don't cache revocation info. We will
* check signatures if the keyring has unchecked revocation signatures
* where the key does not have the revoke flag cached.
*/
if( IsPGPError( err = sIsSigCheckNeeded( set, &sigCheckNeeded ) ) )
goto error;
if( sigCheckNeeded )
{
if ( IsPGPError( err = PGPCheckKeyRingSigs( set, set, FALSE,
NULL, NULL ) ) )
goto error;
if ( IsPGPError( err = PGPPropagateTrust( set ) ) )
goto error;
if ( PGPKeySetIsMutable( set ) )
{
if ( IsPGPError( err = PGPCommitKeyRingChanges( set ) ) )
goto error;
}
} else {
/* We will re-run trust propagation if anything has expired */
RingSet const *ringset = pgpKeyDBRingSet( dbunion );
curTime = PGPGetTime();
if( ringSetHasExpiringObjects( ringset, curTime, pubModTime ) ) {
if ( IsPGPError( err = PGPPropagateTrust( set ) ) )
goto error;
}
}
err = kPGPError_NoErr;
error:
if (dbsec != NULL)
pgpFreeKeyDB(dbsec);
if (dbpub != NULL)
pgpFreeKeyDB(dbpub);
if (dbunion != NULL)
pgpFreeKeyDB(dbunion);
if (set != NULL && IsPGPError( err ))
{
PGPFreeKeySet(set);
set = NULL;
}
*keySetOut = set;
pgpAssertErrWithPtr( err, *keySetOut );
return err;
}
/*
* Open a single specified keyring for user, return keyset for it.
* If isMutable is false, keyrings are read only.
* If isTrusted is false, trust packets are ignored.
*/
PGPError
PGPOpenKeyRing(
PGPContextRef cdkContext,
PGPKeyRingOpenFlags openFlags,
PGPFileSpecRef fileRefIn,
PGPKeySetRef * keySetOut )
{
PGPKeyDB *db = NULL;
PGPKeySet *set = NULL;
RingPool *pgpRingPool;
PGPBoolean sigCheckNeeded;
PGPError err = kPGPError_NoErr;
PFLFileSpecRef fileRef = (PFLFileSpecRef)fileRefIn;
PGPValidatePtr( keySetOut );
*keySetOut = NULL;
PGPValidateContext( cdkContext );
PFLValidateFileSpec( fileRef );
pgpAssert( (openFlags & kPGPKeyRingOpenFlags_Reserved) == 0 );
pgpRingPool = pgpContextGetRingPool( cdkContext );
/* Create key database for this files. Don't bother with keypool. */
if ((db = pgpCreateFileKeyDB(cdkContext, fileRef, openFlags,
pgpRingPool, &err)) == NULL)
goto error;
err = pgpBuildKeyPool(db, 0);
if ( IsPGPError( err ) )
goto error;
set = pgpKeyDBRootSet(db);
if ( IsNull( set ) )
{
err = kPGPError_OutOfMemory; /* XXX Improve error */
goto error;
}
/*
* Some earlier versions of PGP don't cache revocation info. We will
* check signatures if the keyring has unchecked revocation signatures
* where the key does not have the revoke flag cached.
*/
if( IsPGPError( err = sIsSigCheckNeeded( set, &sigCheckNeeded ) ) )
goto error;
if( sigCheckNeeded )
{
if ( IsPGPError( err = PGPCheckKeyRingSigs( set, set, FALSE,
NULL, NULL ) ) )
goto error;
if ( IsPGPError( err = PGPPropagateTrust( set ) ) )
goto error;
if ( PGPKeySetIsMutable( set ) )
{
if ( IsPGPError( err = PGPCommitKeyRingChanges( set ) ) )
goto error;
}
}
err = kPGPError_NoErr;
error:
if (db != NULL)
pgpFreeKeyDB(db);
if (set != NULL && IsPGPError( err ))
{
PGPFreeKeySet(set);
set = NULL;
}
*keySetOut = set;
pgpAssertErrWithPtr( err, *keySetOut );
return err;
}
/*
* Add keys to a keyset from a dynamically allocated binary key buffer.
* Makes a copy of the binary key buffer data, so caller can dispose of
* it after this call.
*/
PGPError
pgpImportKeyBinary (
PGPContextRef cdkContext,
PGPByte *buffer,
size_t length,
PGPKeySetRef * outRef
)
{
PGPKeyDBRef kdb;
PGPKeySetRef set = NULL;
RingPool *pgpRingPool;
PGPError err = kPGPError_NoErr;
*outRef = NULL;
/* Create a file type KeyDB from the buffer */
pgpRingPool = pgpContextGetRingPool( cdkContext );
kdb = pgpCreateMemFileKeyDB (cdkContext, buffer, length, pgpRingPool,
&err);
if ( IsNull( kdb ) )
{
pgpAssert( IsPGPError( err ) );
}
else
{
err = pgpBuildKeyPool (kdb, 0);
if ( IsntPGPError( err ) )
{
set = pgpKeyDBRootSet (kdb);
}
pgpFreeKeyDB (kdb);
}
*outRef = set;
return err;
}
/* Import an x509 cert from the specified optionlist input */
static PGPError
sImportX509Certificate( PGPContextRef context, PGPKeySetRef *keys,
PGPInputFormat inputFormat, PGPOptionListRef optionList)
{
PGPByte *bufPtr;
PGPSize bufLength;
PGPByte *outBuf=NULL, *certSet=NULL;
PGPSize outBufLength, certSetLength;
PGPBoolean mustFreeBuf = FALSE;
PGPKeySet *keys2 = NULL;
char *passphrase;
PGPSize passphraseLength = 0;
PGPError err = kPGPError_NoErr;
err = pgpSetupInputToBuffer( context, optionList, &bufPtr, &bufLength,
&mustFreeBuf );
if( IsPGPError( err ) )
goto error;
if( inputFormat == kPGPInputFormat_PKCS12 ||
inputFormat == kPGPInputFormat_PrivateKeyInfo )
{
/* Input a private X.509 key */
RingObject *key = NULL;
if( inputFormat == kPGPInputFormat_PKCS12 )
{
/* Pick up optional passphrase */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_Passphrase, FALSE,
"%p%l", &passphrase, &passphraseLength ) ) )
goto error;
err = PKCS12InputKey( context, bufPtr, bufLength,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -