📄 pgpkeysig.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
Check and create keyring signatures
$Id: pgpKeySig.c,v 1.37 2002/08/06 20:11:00 dallen Exp $
____________________________________________________________________________*/
#include "pgpConfig.h"
#include "pgpDebug.h"
#include "pgpMakeSig.h"
#include "pgpMem.h"
#include "pgpPktByte.h"
#include "pgpRegExp.h"
#include "pgpKeyPriv.h"
#include "pgpTimeDate.h"
#include "pgpHashPriv.h"
#include "pgpErrors.h"
#include "pgpPubKey.h"
#include "pgpSig.h"
#include "pgpSigSpec.h"
#include "pgpTrustPriv.h"
#include "pgpUsuals.h"
#include "pgpTypes.h"
#include "pgpX509Priv.h"
#include "pgpOptionListPriv.h"
/*
* Keyring signature checking code.
*/
/* Callback for checking function */
typedef struct PGPKeyCheckState {
PGPContextRef context;
PGPEventHandlerProcPtr progress;
PGPUserValue userValue;
PGPUInt32 total;
PGPUInt32 sofar;
} PGPKeyCheckState;
static PGPError
sCheckCRLs( PGPKeySet *keyset, int allflag, PGPKeyDBRef otherdb,
PGPKeySetRef changedSet );
static PGPBoolean
sCheckableSig( PGPKeyDBObj const *sig, PGPKeyDB *otherdb,
PGPBoolean allflag, PGPBoolean revocationonly, PGPKeyDBObj **retsignkey);
static void
sUncheckSig( PGPKeyDBObj *sig, PGPKeyDB *keydb, PGPBoolean *changed );
static PGPError
sCheckSig(PGPKeyDBObj *sig, PGPKeyDBObj *key, PGPBoolean *changed,
PGPBoolean *verified );
static PGPError
sCheckKeysCallback(void *arg, PGPKeyDBObj *obj, int status)
{
PGPKeyCheckState *s = (PGPKeyCheckState *)arg;
PGPError err = kPGPError_NoErr;
PGPOptionListRef newOptionList = NULL;
(void) obj;
(void) status;
if (IsntNull (s->progress)) {
err = pgpEventNull (s->context, &newOptionList,
s->progress, s->userValue, ++s->sofar, s->total);
if (IsntNull (newOptionList))
pgpFreeOptionList (newOptionList);
}
return err;
}
/* Called on the back end from the front end preparatory to doing a one
* key at a time series of key checks.
*/
PGPError
pgpPrepareToCheckKeyRingSigs_internal( PGPKeySetRef keysToCheck,
PGPKeyDBRef otherDB, PGPBoolean checkAll, PGPUInt32 *nsigs,
PGPKeySetRef changedSet )
{
PGPError err;
*nsigs = pgpCountCheckableKeySigs( keysToCheck, otherDB, checkAll, FALSE );
err = sCheckCRLs( keysToCheck, checkAll, NULL, changedSet );
if( IsPGPError( err ) )
return err;
if( IsntNull( otherDB ) )
{
/* Must check CRLs in otherdb against this one */
PGPKeySetRef oroot = PGPPeekKeyDBRootKeySet( otherDB );
PGPKeyDBRef keydb = PGPPeekKeySetKeyDB( keysToCheck );
if( IsPGPError( err = sCheckCRLs( oroot, checkAll,
keydb, changedSet ) ) )
return err;
}
return kPGPError_NoErr;
}
PGPError
pgpCheckKeyRingSigs_internal( PGPKeySetRef keysToCheck, PGPKeyDBRef otherDB,
PGPBoolean checkAll, PGPEventHandlerProcPtr eventHandler,
PGPUserValue eventHandlerData, PGPKeySetRef changeSet )
{
PGPKeyCheckState s;
s.context = PGPPeekKeySetContext( keysToCheck );
s.progress = eventHandler;
s.userValue = eventHandlerData;
s.sofar = 0;
if( IsntNull( eventHandler ) )
{
s.total = pgpCountCheckableKeySigs( keysToCheck, otherDB, checkAll,
FALSE );
}
return pgpCheckKeySigs( keysToCheck, otherDB, checkAll, FALSE, FALSE,
sCheckKeysCallback, &s, changeSet );
}
PGPError
PGPCheckKeyRingSigs( PGPKeySetRef keysToCheck, PGPKeyDBRef otherDB,
PGPBoolean checkAll, PGPEventHandlerProcPtr eventHandler,
PGPUserValue eventHandlerData )
{
PGPKeyDBRef setDB;
PGPKeySetRef changedSet;
PGPError err;
PGPUInt32 nsigs;
PGPKeyCheckState s;
PGPValidateKeySet( keysToCheck );
if( IsntNull( otherDB ) )
PGPValidateKeyDB( otherDB );
pgpEnterPGPErrorFunction();
setDB = PGPPeekKeySetKeyDB( keysToCheck );
if( otherDB == setDB )
otherDB = NULL;
if( pgpFrontEndKeyDB( setDB ) )
{
PGPUInt32 *keylist;
PGPSize keylistsize;
PGPUInt32 *changelist;
PGPSize changelistsize;
PGPContextRef context = PGPPeekKeyDBContext( setDB );
if( IsNull( eventHandler ) )
{
/* Do it all in background if he doesn't want events */
err = pgpKeySetFlatten( keysToCheck, &keylist, &keylistsize );
if( IsPGPError( err ) )
return err;
err = pgpCheckKeyRingSigs_back( context, setDB->id, keylist,
keylistsize,
(IsNull(otherDB)?0:otherDB->id),
checkAll, &changelist,
&changelistsize );
if( IsPGPError( err ) )
return err;
err = pgpKeyRefreshFromList( setDB, changelist, changelistsize );
if( IsPGPError( err ) )
return err;
return PGPCalculateTrust( keysToCheck, otherDB );
}
/* Else he wants events, must do it one at a time */
err = pgpKeySetFlatten( keysToCheck, &keylist, &keylistsize );
if( IsPGPError( err ) )
return err;
err = pgpPrepareToCheckKeyRingSigs_back( context, setDB->id,
keylist, keylistsize,
(IsNull(otherDB)?0:otherDB->id),
checkAll, &nsigs, &changelist,
&changelistsize );
if( IsPGPError( err ) )
return err;
if( IsPGPError( err = pgpKeySetUnflattenFree( setDB, changelist,
changelistsize,
&changedSet ) ) )
return err;
s.context = context;
s.progress = eventHandler;
s.userValue = eventHandlerData;
s.sofar = 0;
s.total = nsigs;
err = pgpCheckKeySigs( keysToCheck, otherDB, checkAll, FALSE, TRUE,
sCheckKeysCallback, &s, changedSet );
if( IsPGPError( err ) )
{
PGPFreeKeySet( changedSet );
return err;
}
if( IsPGPError( err = pgpKeySetRefreshFree( changedSet ) ) )
return err;
return PGPCalculateTrust( keysToCheck, otherDB );
}
err = pgpCheckKeyRingSigs_internal( keysToCheck, otherDB, checkAll,
eventHandler, eventHandlerData,
NULL );
if( IsPGPError( err ) )
return err;
return PGPCalculateTrust( keysToCheck, otherDB );
}
/*
* Count the number of sigs we would check with pgpCheckKeySigs.
* The return value is the number of times the progress func() function
* will be called by pgpCheckKeySigs().
* NOTE: this tries to be as accurate as possible, but user code
* should not die if it is slightly incorrect.
*/
PGPUInt32
pgpCountCheckableKeySigs(PGPKeySet *keyset, PGPKeyDB *otherdb,
PGPBoolean allflag, PGPBoolean revocationonly)
{
PGPKeyDB *keydb;
PGPKeyDBObj *key;
PGPKeyDBObj *child;
PGPKeyDBObj *gchild;
PGPKeyDBObj *signkey;
PGPUInt32 count = 0;
keydb = PGPPeekKeySetKeyDB( keyset );
for( key = keydb->firstKeyInDB; IsntNull( key ); key = key->next)
{
if( !pgpKeyDBObjIsReal( key ) )
continue;
if( !pgpKeySetIsMember( key, keyset ) )
continue;
for( child = key->down; IsntNull( child ); child = child->next)
{
if( !pgpKeyDBObjIsReal( child ) )
continue;
if( !pgpKeySetIsMember( child, keyset ) )
continue;
if( pgpObjectType( child ) == RINGTYPE_SIG &&
sCheckableSig( child, otherdb,
allflag, revocationonly, &signkey ) )
{
if( IsntNull( signkey ) )
++count;
}
for( gchild = child->down; IsntNull(gchild); gchild = gchild->next)
{
if( !pgpKeyDBObjIsReal( gchild ) )
continue;
if( !pgpKeySetIsMember( gchild, keyset ) )
continue;
if( pgpObjectType( gchild ) == RINGTYPE_SIG &&
sCheckableSig( gchild, otherdb,
allflag, revocationonly, &signkey ) )
{
if( IsntNull( signkey ) )
++count;
}
}
}
}
return count;
}
/* True if signature would be checked given the specified parameters */
/* Return *retsignkey as signing key if we return TRUE */
static PGPBoolean
sCheckableSig( PGPKeyDBObj const *sig, PGPKeyDB *otherdb,
PGPBoolean allflag, PGPBoolean revocationonly, PGPKeyDBObj **retsignkey)
{
PGPKeyDBObj * signkey;
PGPKeyID signkeyid;
PGPSigInfo * sinfo;
PGPByte sigalg;
PGPError err;
if( IsntNull( retsignkey ) )
*retsignkey = NULL;
pgpAssert( pgpObjectType( sig ) == RINGTYPE_SIG );
sinfo = pgpSigToSigInfo( sig );
signkey = sinfo->by;
if( !pgpKeyDBObjIsReal( signkey ) )
{
if( IsNull( otherdb ) )
{
/* leave *retsignkey as NULL so caller knows we don't have it */
return TRUE;
}
/* Else see if it is in other db */
pgpSigID8( sig, &sigalg, &signkeyid );
err = pgpGetKeyByKeyID(otherdb, &signkeyid, TRUE, FALSE, &signkey );
if( IsPGPError( err ) )
return FALSE;
if( !pgpKeyDBObjIsReal( signkey ) )
{
/* leave *retsignkey as NULL so caller knows we don't have it */
return TRUE;
}
}
if ( (allflag || !(sinfo->trust & (PGP_SIGTRUSTF_CHECKED_TRIED |
PGP_SIGTRUSTF_REVOKEDBYCRL)))
&& (!revocationonly || sinfo->type == PGP_SIGTYPE_KEY_REVOKE) )
{
if( IsntNull( retsignkey ) )
*retsignkey = signkey;
return TRUE;
}
return FALSE;
}
/* Compare an object with a buffer */
static PGPBoolean
sObjDiffers( PGPKeyDBObj *obj, PGPByte *buf, PGPSize len )
{
PGPBoolean mustFree = FALSE;
PGPBoolean match = FALSE;
PGPByte const *objdata;
PGPSize objlen;
PGPSize hlen;
/* Fetch public version of secret key for this */
if( OBJISKEY( obj ) && pgpKeyIsSec( obj ) )
{
objdata = pgpKeyDBObjToPubData( obj, &objlen );
mustFree = TRUE;
} else {
objdata = pgpFetchObject( obj, &objlen );
}
hlen = pgpPktBufferHeaderLen( objdata );
if( len == objlen-hlen && pgpMemoryEqual( objdata+hlen, buf, len ) )
match = TRUE;
if( mustFree )
PGPFreeData( (PGPByte *)objdata );
return !match;
}
/* True if X.509 sig is valid */
static PGPBoolean
pgpSigX509Valid (PGPKeyDBObj *obj, PGPKeyDBObjRef key )
{
PGPASN_Certificate *cert = NULL;
PGPPubKey const *pub = NULL;
PGPByte *buf;
PGPByte *x509cert;
PGPSize len;
PGPSize x509len;
PGPKeyDBRef keydb;
PGPContextRef context;
PGPKeyDBObj *parentkey;
PGPKeyDBObj *parentuserid;
PGPByte loversion;
MemPool mempoolinit;
PGPError err = kPGPError_NoErr;
/*
* Steps:
* 1) Compare the key and userid data with that in the cert.
* 2) Validate the signature in the cert, using pub
*/
keydb = PGPPeekKeyDBObjKeyDB( obj );
context = PGPPeekKeyDBContext( keydb );
mempoolinit = keydb->objPool;
pub = pgpKeyPubKey( key, PGP_PKUSE_SIGN );
if( IsNull( pub ) )
goto error;
parentuserid = obj->up;
if( !OBJISUSERID(parentuserid) )
goto error;
parentkey = parentuserid->up;
if( !OBJISTOPKEY(parentkey) )
goto error;
/* Find embedded X509 cert */
buf = (PGPByte *)pgpFetchObject(obj, &len);
if( IsNull( buf ) )
goto error;
x509cert = (PGPByte *)pgpSigFindNAISubSubpacket(buf, SIGSUBSUB_X509, 0,
&x509len, NULL, NULL, NULL, NULL);
if( IsNull( x509cert ) )
goto error;
/* Check type, version bytes */
if( x509len < 3 )
goto error;
pgpAssert (x509cert[0] == SIGSUBSUB_X509);
if( x509cert[1] != SIGSUBSUB_X509_VERSION_HI )
goto error;
loversion = x509cert[2];
x509cert += 3;
x509len -= 3;
err = pgpX509VerifySignedObject( context, pub, x509cert, x509len );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -