📄 pgpkeyobj.c
字号:
* first. Then, we take the latest self signature on the primary userid
* of the key and we see whether it has the subpacket of interest.
* So there is one revocable self signature that counts, and it is the
* latest one. Plus, all the nonrevocable self sigs count.
*
* pmatches is filled in with the total
* number of instances in all packets. The plen, pcritical, phashed,
* and pcreated values are filled in with the signature packet
* corresponding to the nth instance of the data we want.
*
* key key to use
* subpacktype subpacket type to search for
* nth nth matching subpacket to find
* *plen return length of data
* *pcritical return criticality field of subpacket
* *phashed return whether subpacket was in hashed region
* *pcreation return creation time of matching signature
* *pmatches return number of matches of this subpack type
* *error return error code
*
* Function returns pointer to the data, of length *plen, or NULL with *error
* set for error code. If matching packet is not found, return NULL
* with *error = 0.
*/
PGPByte const *
pgpKeyFindSubpacket (PGPKeyDBObj *obj, int subpacktype, unsigned nth,
PGPSize *plen, PGPBoolean *pcritical, PGPBoolean *phashed,
PGPUInt32 *pcreation, PGPUInt32 *pmatches, PGPError *error)
{
PGPKeyDBObj *sig, *bestsig, *lookobj, *signobj;
PGPKeyDBObj *child;
PGPKeyDBObj *primaryUserid;
PGPSigInfo * sinfo;
PGPUInt32 bestcreation;
PGPUInt32 totalmatches;
PGPByte const *bestp;
PGPSize bestlen;
PGPBoolean bestcritical;
PGPBoolean besthashed;
int level;
pgpAssert(OBJISKEY(obj));
signobj = OBJISTOPKEY(obj) ? obj : obj->up;
primaryUserid = pgpKeyPrimaryUserID( signobj, 0 );
bestlen = bestcritical = besthashed = bestcreation = 0;
totalmatches = 0;
sig = NULL;
bestp = NULL;
bestsig = NULL;
if (error)
*error = kPGPError_NoErr;
/* First look for nonrevocable signatures */
for (child = obj->down; IsntNull(child); child = child->next)
{
if( !pgpKeyDBObjIsReal( child ) )
continue;
/* Kludge here to look for sigs at either level 2 or level 3 */
if( OBJISSIG( child ) )
{
sig = child;
level = 2;
} else {
sig = child->down;
level = 3;
}
/* This does one pass for level 2 sigs, or multiples for level 3 */
for ( ; IsntNull( sig ) ; sig = (level == 2) ? NULL : sig->next )
{
/* Abort when we come to another key or subkey. */
if (OBJISKEY(sig))
goto done1;
if( !OBJISSIG(sig))
continue;
if( !pgpKeyDBObjIsReal(sig) )
continue;
/* Only count self-sigs that have been validated */
if (pgpSigMaker (sig) != signobj)
continue;
if ((pgpSigType (sig) & 0xf0) != PGP_SIGTYPE_KEY_GENERIC)
continue;
if (!pgpSigChecked (sig))
continue;
sinfo = pgpSigToSigInfo( sig );
if (SIGISREVOCABLE(sinfo))
continue;
/* Here we have a nonrevocable self signature */
*error = sFindSubpacket( sig, subpacktype, nth, &bestp, &bestlen,
&bestcritical, &besthashed, &bestcreation,
&totalmatches, &bestsig );
if( IsPGPError( *error ) )
return NULL;
/* If don't need to count all matches, done now */
if( IsNull( pmatches ) && IsntNull( bestsig ) )
break;
}
}
done1:
/* Second, on subkey, look below it; on key, look below primary */
if( OBJISSUBKEY(obj) )
lookobj = obj;
else
lookobj = primaryUserid;
/* Only check if we don't have bestsig yet or we are returning matches */
if (IsntNull(lookobj) && (IsNull(bestsig) || IsntNull(pmatches)))
{
sig = pgpLatestSigByKey( lookobj, signobj );
if (sig)
{
sinfo = pgpSigToSigInfo( sig );
if (SIGISREVOCABLE(sinfo))
{
*error = sFindSubpacket( sig, subpacktype, nth, &bestp,
&bestlen, &bestcritical, &besthashed,
&bestcreation, &totalmatches,
&bestsig );
if( IsPGPError( *error ) )
return NULL;
}
}
}
/* Third, look at other userids */
/* Only check if we don't have bestsig yet or we are returning matches */
if (IsntNull(lookobj) && (IsNull(bestsig) || IsntNull(pmatches)))
{
for (lookobj = signobj->down; IsntNull(lookobj); lookobj=lookobj->next)
{
if( !pgpKeyDBObjIsReal( lookobj ) )
continue;
if( !OBJISUSERID( lookobj ) )
continue;
if( lookobj == primaryUserid )
continue;
sig = pgpLatestSigByKey( lookobj, signobj );
if (sig)
{
sinfo = pgpSigToSigInfo( sig );
if (SIGISREVOCABLE(sinfo))
{
*error = sFindSubpacket( sig, subpacktype, nth, &bestp,
&bestlen, &bestcritical,
&besthashed, &bestcreation,
&totalmatches, &bestsig );
if( IsPGPError( *error ) )
return NULL;
}
}
/* If don't need to count all matches, done now */
if( IsNull( pmatches ) && IsntNull( bestsig ) )
break;
}
}
/* Fourth, check sigs directly below signing key */
/* Only check if we don't have bestsig yet or we are returning matches */
if( OBJISKEY( signobj ) && (IsNull(bestsig) || IsntNull(pmatches)))
{
lookobj = signobj;
sig = pgpLatestSigByKey( lookobj, signobj );
if (sig)
{
sinfo = pgpSigToSigInfo( sig );
if (SIGISREVOCABLE(sinfo))
{
*error = sFindSubpacket( sig, subpacktype, nth, &bestp,
&bestlen, &bestcritical, &besthashed,
&bestcreation, &totalmatches,
&bestsig );
if( IsPGPError( *error ) )
return NULL;
}
}
}
if (plen)
*plen = bestlen;
if (pcritical)
*pcritical = bestcritical;
if (phashed)
*phashed = besthashed;
if (pcreation)
*pcreation = bestcreation;
if (pmatches)
*pmatches = totalmatches;
return bestp;
}
/*
* Find an additional decryption key for the given key, if one exists.
* nth tells which one to find. *pkeys is set to the number of add'l
* decryption keys, *pclass is set to the class byte associated with
* the decryption key. *pkalg and *keyid are set to the algorithm and
* keyid of the nth ADK key. Returns NULL but no error in *error if
* the ADK key is not found. Return *error as
* kPGPError_ItemNotFound if there are fewer than n+1 ADKs.
*/
PGPKeyDBObj *
pgpKeyAdditionalRecipientRequestKey (PGPKeyDBObj *obj,
unsigned nth, PGPByte *pkalg, PGPKeyID *keyid,
PGPByte *pclass, unsigned *pkeys, PGPError *error)
{
PGPKeyDBObj *rkey; /* Additional decryption key */
PGPByte const *krpdata; /* Pointer to key decryption data */
PGPSize krdatalen; /* Length of krdata */
PGPBoolean critical; /* True if decryption field was critical */
PGPBoolean hashed; /* True if was in hashed region */
unsigned matches; /* Number of adk's found */
PGPByte fingerp[20]; /* Fingerprint of adk */
PGPByte krdata[22]; /* Copy of key decryption data packet */
pgpAssert(OBJISKEY(obj));
pgpAssert (error);
*error = kPGPError_NoErr;
if( IsntNull( pkeys ) )
*pkeys = 0;
if( IsntNull( pclass ) )
*pclass = 0;
if( IsntNull( pkalg ) )
*pkalg = 0;
if( IsntNull( keyid ) )
{
pgpClearMemory( keyid, sizeof( *keyid ) );
}
krpdata = pgpKeyFindSubpacket (obj,
SIGSUB_KEY_ADDITIONAL_RECIPIENT_REQUEST, nth, &krdatalen,
&critical, &hashed, NULL, &matches, error);
if (!krpdata || !hashed) {
if (IsntPGPError(*error))
*error = kPGPError_ItemNotFound;
return NULL;
}
/*
* krdata is 1 byte of class, 1 of pkalg, 20 bytes of fingerprint.
* Last 8 of 20 are keyid. Make a copy because data is volatile when
* we do other operations.
*/
if (krdatalen < sizeof(krdata)) {
/* malformed packet, can't use it */
*error = kPGPError_ItemNotFound;
return NULL;
}
pgpCopyMemory (krpdata, krdata, sizeof(krdata));
/* Do we have ADK? */
rkey = pgpKeyById8 (PGPPeekKeyDBObjKeyDB(obj), krdata[1],krdata+2+20-8);
if (IsntNull (rkey)) {
if( pgpKeyDBObjIsDummy( rkey ) ) {
rkey = NULL;
} else {
pgpKeyFingerprint20 (rkey, fingerp);
if (memcmp (fingerp, krdata+2, 20) != 0) {
/* Have a key that matches in keyid but wrong fingerprint */
rkey = NULL;
}
}
}
/* Success */
if (pkeys) {
*pkeys = matches;
}
if (pclass) {
*pclass = krdata[0];
}
if (pkalg) {
*pkalg = krdata[1];
}
if (keyid) {
pgpNewKeyIDFromRawData( krdata+2+20-8, krdata[1], 8, keyid );
}
return rkey;
}
/*
* Find a key revocation key and keyid for the given key. nth tells
* which one to find. *pkeys is set to the number of key revocation
* keys, *pclass is set to the class byte associated with the
* revocation key. Returns NULL but no error in *error if the ADK key
* is not found. Return *error as
* kPGPError_ItemNotFound if there are fewer than n+1 ADKs. The class
* byte is intended for future expansion; for now the high order bit
* is used to indicate a revocation authorization. Later we could use
* the other bits to authorize other kinds of signatures, perhaps.
*/
PGPKeyDBObj *
pgpKeyRevocationKey (PGPKeyDBObj *obj, unsigned nth,
PGPByte *pkalg, PGPKeyID *keyid, PGPByte *pclass, unsigned *pkeys,
PGPError *error)
{
PGPKeyDBObj *rkey; /* Message revocation key */
PGPByte const *krpdata; /* Pointer to key revocation data */
PGPSize krdatalen; /* Length of krdata */
PGPBoolean critical; /* True if revocation field was critical */
PGPBoolean hashed; /* True if in hashed region (must be) */
unsigned matches; /* Number of revkey packets found */
PGPByte fingerp[20]; /* Fingerprint of revkey */
PGPByte krdata[22]; /* Copy of key revocation data packet */
pgpAssert(OBJISKEY(obj));
pgpAssert (error);
*error = kPGPError_NoErr;
if( IsntNull( pkeys ) )
*pkeys = 0;
if( IsntNull( pclass ) )
*pclass = 0;
if( IsntNull( pkalg ) )
*pkalg = 0;
if( IsntNull( keyid ) )
{
pgpClearMemory( keyid, sizeof( *keyid ) );
}
krpdata = pgpKeyFindSubpacket (obj, SIGSUB_KEY_REVOCATION_KEY, nth,
&krdatalen, &critical, &hashed, NULL, &matches, error);
if (!krpdata || !hashed) {
if (IsntPGPError(*error))
*error = kPGPError_ItemNotFound;
return NULL;
}
/*
* krdata is 1 byte of class, 1 of pkalg, 20 bytes of fingerprint.
* Last 8 of 20 are keyid. Make a copy because data is volatile when
* we do other operations.
*/
if (krdatalen < sizeof(krdata)) {
/* malformed packet, can't use it */
*error = kPGPError_ItemNotFound;
return NULL;
}
pgpCopyMemory (krpdata, krdata, sizeof(krdata));
/* Do we have revocation packet? */
rkey = pgpKeyById8 (PGPPeekKeyDBObjKeyDB(obj), krdata[1],krdata+2+20-8);
if (IsntNull (rkey) ) {
if (pgpKeyDBObjIsDummy( rkey ) ) {
rkey = NULL;
} else {
pgpKeyFingerprint20 (rkey, fingerp);
if (memcmp (fingerp, krdata+2, 20) != 0) {
/* Have a key that matches in keyid but wrong fingerprint */
rkey = NULL;
}
}
}
/* Else success */
if (pkeys) {
*pkeys = matches;
}
if (pclass) {
*pclass = krdata[0];
}
if (pkalg) {
*pkalg = krdata[1];
}
if (keyid) {
pgpNewKeyIDFromRawData( krdata+2+20-8, krdata[1], 8, keyid );
}
return rkey;
}
/*
* Return true if rkey is a revocation key for key.
* Includes case where rkey is a dummy key which has issued a signature
* but is not local to the keyring. In that case we just check for match
* on keyid and pkalg.
*/
PGPBoolean
pgpKeyIsRevocationKey (PGPKeyDBObj *key, PGPKeyDBObj *rkey)
{
PGPByte revClass;
PGPUInt32 nRevKeys;
PGPUInt32 iRevKeys;
PGPByte revAlg;
PGPByte rKeyAlg;
PGPKeyID revKeyID;
PGPKeyID rKeyID;
PGPBoolean nonLocal;
PGPError error;
nonLocal = pgpKeyDBObjIsDummy(rkey);
if (nonLocal) {
pgpKeyID8 (rkey, &rKeyAlg, &rKeyID);
}
nRevKeys = 1;
iRevKeys = 0;
while (iRevKeys < nRevKeys) {
PGPKeyDBObj const *revkey;
revkey = pgpKeyRevocationKey(key, iRevKeys++, &revAlg, &revKeyID,
&revClass, &nRevKeys, &error);
if (IsPGPError(error))
break;
if (!(revClass & 0x80))
continue;
if (nonLocal) {
if (rKeyAlg == revAlg &&
0 == PGPCompareKeyIDs (&rKeyID, &revKeyID))
return TRUE;
} else if (revkey == rkey) {
return TRUE;
}
}
return FALSE;
}
/*
* True if there is a third party revocation signature on the given
* key. Return the key (if local) and the keyid of the revoking key.
* Note that this requires that there be both a revoking authorization
* on the revoker key and a revocation issued by that key.
*/
PGPBoolean
pgpKeyHasThirdPartyRevocation (PGPKeyDBObj *obj,
PGPKeyDBObj **revkey, PGPByte *pkalg, PGPKeyID *keyid, PGPError *error)
{
PGPSigInfo *sinfo = NULL;
PGPKeyDBObj *topkey;
PGPKeyDBObj *sig;
PGPByte rKeyAlg;
PGPKeyID rKeyID;
pgpAssert(OBJISKEY(obj));
pgpAssert (error);
*error = kPGPError_NoErr;
if( IsntNull( revkey ) )
*revkey = NULL;
if( IsntNull( pkalg ) )
*pkalg = 0;
if( IsntNull( keyid ) )
{
pgpClearMemory( keyid, sizeof( *keyid ) );
}
/* May be called on subkey, so find top level key */
topkey = obj;
if (OBJISSUBKEY(topkey))
topkey = pgpKeyMasterkey (topkey );
/* Search for a revocation signature on this key */
for (sig=obj->down; IsntNull(sig); sig=sig->next) {
if( !pgpKeyDBObjIsReal(sig) )
continue;
if (!OBJISSIG(sig))
continue;
sinfo = pgpSigToSigInfo( sig );
if (sinfo->type != ( (topkey==obj) ? PGP_SIGTYPE_KEY_REVOKE
: PGP_SIGTYPE_KEY_SUBKEY_REVOKE ))
continue;
if (sinfo->by == topkey)
continue;
if (pgpKeyIsRevocationKey (topkey, sinfo->by))
break;
}
if (IsNull (sig)) {
/* No luck */
return FALSE;
}
if( IsntNull( revkey ) ) {
if( !pgpKeyDBObjIsDummy( sinfo->by ) )
*revkey = sinfo->by;
}
pgpKeyID8 (sinfo->by, &rKeyAlg, &rKeyID);
if (pkalg) {
*pkalg = rKeyAlg;
}
if (keyid) {
*keyid = rKeyID;
}
return TRUE;
}
/*
* Create a SigSpec structure which represents the given signature.
* We must have the signing key as a private key. We would have to
* change the initialization of pgpSigSpec to avoid this, but normally
* the reason for doing this is to re-issue a modified signature, so it
* is a reasonable restriction.
*/
PGPSigSpec *
pgpSigSigSpec (PGPKeyDBObj *sig, PGPError *error)
{
PGPContextRef cdkContext;
PGPEnv *env;
PGPSigInfo *sinfo;
PGPByte *p;
PGPSigSpec *spec;
PGPSize len;
PGPSize hlen;
pgpAssert(OBJISSIG(sig));
pgpAssert( IsntNull( error ) );
*error = kPGPError_NoErr;
sinfo = pgpSigToSigInfo( sig );
cdkContext = PGPPeekKeyDBContext(PGPPeekKeyDBObjKeyDB( sig ) );
env = pgpContextGetEnvironment( cdkContext );
spec = pgpSigSpecCreate (env, sinfo->by, sinfo->type);
if( IsNull( spec ) ) {
*error = kPGPError_OutOfMemory;
return NULL;
}
/* Fetch data for sig */
p = (PGPByte *)pgpFetchObject(sig, &len);
if( IsNull( p ) ) {
pgpSigSpecDestroy (spec);
*error = pgpKeyDBError( PGPPeekKeyDBObjKeyDB(sig) );
return NULL;
}
hlen = pgpPktBufferHeaderLen( p );
pgpSigSpecSetHashtype (spec, sinfo->hashalg);
pgpSigSpecSetVersion (spec, p[hlen]);
pgpSigSpecSetTimestamp (spec, sinf
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -