📄 pgpkeyadd.c
字号:
PGPKeyDBObj *casig;
PGPKeyDBObj *child;
PGPKeyDBObj *gchild;
PGPByte const *sigbuf;
PGPSize siglen;
PGPByte issuerbytes[8];
PGPByte subjectbytes[8];
PGPKeyID keyID;
PGPByte pkalg;
pgpAssert( OBJISTOPKEY( cakey ) );
/* Find CA signature so we can get subject name */
casig = NULL;
for( child = cakey->down; IsntNull(child) && IsNull(casig);
child = child->next )
{
if( !pgpKeyDBObjIsReal( child ) )
continue;
if( OBJISSIG( child ) && pgpSigIsX509( child ) )
{
casig = child;
break;
}
for( gchild = child->down; IsntNull(gchild); gchild=gchild->next )
{
if( !pgpKeyDBObjIsReal( gchild ) )
continue;
if( OBJISSIG( gchild ) && pgpSigIsX509( gchild ) )
{
casig = gchild;
break;
}
}
}
/* Probably casig shouldn't be able to be null here */
if( casig == NULL )
return NULL;
sigbuf = pgpFetchObject( casig, &siglen );
sX509KeyIDBytes( kdb, sigbuf, siglen, NULL, issuerbytes, subjectbytes );
pkalg = 0x80;
pgpNewKeyIDFromRawData( subjectbytes, pkalg, 8, &keyID );
pgpGetKeyByKeyID( kdb, &keyID, TRUE, FALSE, &x509key );
return x509key;
}
/*
* See if object matches the given buffer. Ignores differences in header
* tag/length formatting.
*/
static PGPBoolean
sObjectMatchesBuffer( PGPKeyDBObj const *obj, PGPByte const *buf, PGPSize len )
{
PGPByte const *objbuf;
PGPSize objlen;
PGPSize objheaderlen, bufheaderlen;
PGPByte buftype, objtype;
/* Skip buffer past header */
buftype = PKTBYTE_TYPE(*buf);
bufheaderlen = pgpPktBufferHeaderLen( buf );
buf += bufheaderlen;
len -= bufheaderlen;
objbuf = pgpFetchObject( obj, &objlen );
objtype = PKTBYTE_TYPE(*objbuf);
if( objtype != buftype )
return FALSE;
/* Skip object past header */
objheaderlen = pgpPktBufferHeaderLen( objbuf );
objbuf += objheaderlen;
objlen -= objheaderlen;
return objlen == len && pgpMemoryEqual( objbuf, buf, len );
}
/* Look for a matching object with specified parent. Allow deleteds. */
PGPKeyDBObj *
pgpFindMatchingChild( PGPKeyDBObj *parent, PGPByte const *buf, PGPSize len )
{
PGPKeyDBObj *obj;
for( obj=parent->down; IsntNull( obj ); obj = obj->next )
{
if( sObjectMatchesBuffer( obj, buf, len ) )
break;
}
return obj;
}
/* True if data in a pubkey buffer is consistent with data in a seckey
* buffer. If evidence of version bug, return *vbug as true. The version
* bug happens if the sec buffer says V3 and the pub buffer says V2.
*/
static PGPBoolean
sConsistentPubAndSec( PGPByte const *pdata, PGPSize plen, PGPByte const *sdata,
PGPSize slen, PGPBoolean *vbug )
{
PGPSize secsublen;
PGPSize secheaderlen;
PGPSize pubheaderlen;
PGPByte secver;
PGPByte pubver;
if( IsntNull( vbug ) )
*vbug = FALSE;
pgpAssert( PKTBYTE_TYPE(pdata[0]) == PKTBYTE_PUBKEY ||
PKTBYTE_TYPE(pdata[0]) == PKTBYTE_PUBSUBKEY);
pgpAssert( PKTBYTE_TYPE(sdata[0]) == PKTBYTE_SECKEY ||
PKTBYTE_TYPE(sdata[0]) == PKTBYTE_SECSUBKEY);
secsublen = pgpKeyParsePublicPrefix( sdata, slen );
secheaderlen = pgpPktBufferHeaderLen( sdata );
secver = sdata[secheaderlen];
pubheaderlen = pgpPktBufferHeaderLen( pdata );
pubver = pdata[pubheaderlen];
/* Compare all but version byte. Return false if that doesn't match */
if( secsublen-secheaderlen != plen-pubheaderlen ||
!pgpMemoryEqual( sdata+secheaderlen+1, pdata+pubheaderlen+1,
secsublen-secheaderlen-1 ) )
return FALSE;
/* Okay, they matched. Now compare versions. */
if( secver == pubver )
return TRUE;
/* Versions disagreed, check for version bug, else return false */
if( secver == PGPVERSION_3 && pubver == PGPVERSION_2 )
{
*vbug = TRUE;
return TRUE;
}
return FALSE;
}
/*
* Create a public key buffer from a given private key buffer. Pubkey
* buffer must be freed.
*/
PGPByte *
pgpKeyDBObjToPubData( PGPKeyDBObj *key, PGPSize *retlen )
{
PGPKeyDB * keydb;
PGPContextRef context;
PGPByte const * sdata;
PGPByte * pdata;
PGPSize slen;
PGPSize plen;
PGPSize secsublen;
PGPSize secheaderlen;
PGPSize pubheaderlen;
PGPKeyInfo * kinfo;
PGPByte pubpkttype;
pgpAssert( OBJISKEY( key ) );
pgpAssert( pgpKeyIsSec( key ) );
keydb = PGPPeekKeyDBObjKeyDB( key );
context = PGPPeekKeyDBContext( keydb );
kinfo = pgpKeyToKeyInfo( key );
sdata = pgpFetchObject( key, &slen );
if( IsNull( sdata ) )
return NULL;
if( PKTBYTE_TYPE(sdata[0]) != PKTBYTE_SECKEY &&
PKTBYTE_TYPE(sdata[0]) != PKTBYTE_SECSUBKEY )
{
/* This can happen if secret part is external, on a token */
pgpAssert( PKTBYTE_TYPE(sdata[0]) == PKTBYTE_PUBKEY ||
PKTBYTE_TYPE(sdata[0]) == PKTBYTE_PUBSUBKEY );
pdata = pgpContextMemAlloc( context, slen, 0 );
if( IsNull( pdata ) )
return NULL;
pgpCopyMemory( sdata, pdata, slen );
*retlen = slen;
return pdata;
}
secsublen = pgpKeyParsePublicPrefix( sdata, slen );
secheaderlen = pgpPktBufferHeaderLen( sdata );
pubpkttype = (PKTBYTE_TYPE(sdata[0]) == PKTBYTE_SECKEY)? PKTBYTE_PUBKEY
: PKTBYTE_PUBSUBKEY;
pubpkttype = PKTBYTE_BUILD( pubpkttype, 1 );
pubheaderlen = pgpPktHeaderLen( pubpkttype, secsublen );
plen = secsublen - secheaderlen + pubheaderlen;
/* Allocate space for pub buffer */
pdata = pgpContextMemAlloc( context, plen, 0 );
if( IsNull( pdata ) )
return NULL;
/* Fill buffer */
pgpPktHeaderPut( pdata, pubpkttype, secsublen-secheaderlen );
pgpCopyMemory( sdata+secheaderlen, pdata+pubheaderlen,
secsublen-secheaderlen );
/* Fix version bug */
if( KEYHASVERSIONBUG(kinfo) )
pdata[pubheaderlen] = PGPVERSION_2;
*retlen = plen;
return pdata;
}
PGPKeyDBObj *
pgpAddKey( PGPInt32 pkttype, PGPByte const *buf, PGPSize len,
PGPKeyDB *kdb, PGPKeyDBObj *parent, PGPByte trusted, PGPError *outerr )
{
PGPKeyDBObj * key;
PGPByte pkalg;
PGPByte vpkalg;
PGPUInt16 keybits;
PGPByte keyIDBytes[8];
PGPByte fp20n[20];
PGPUInt32 tstamp;
PGPUInt16 validity;
PGPByte v3;
PGPBoolean fSubkey;
PGPBoolean fSecret;
PGPBoolean fDummy;
PGPByte const * kdata;
PGPSize kdatalen;
PGPKeyInfo * kinfo;
PGPBoolean vbug;
PGPKeyID keyID;
PGPError err;
fSubkey = (pkttype == PKTBYTE_PUBSUBKEY) || (pkttype == PKTBYTE_SECSUBKEY);
fSecret = (pkttype == PKTBYTE_SECKEY) || (pkttype == PKTBYTE_SECSUBKEY);
err = pgpKeyParse(kdb->context, buf, len, &pkalg, keyIDBytes,
fp20n, &keybits, &tstamp, &validity, &v3, fSecret );
if( IsPGPError( err ) )
return NULL;
vpkalg = pkalg; /* Viacrypt correction */
if ((vpkalg | 1) == 3)
vpkalg = 1;
pgpNewKeyIDFromRawData( keyIDBytes, vpkalg, sizeof(keyIDBytes), &keyID );
fSubkey = (pkttype == PKTBYTE_PUBSUBKEY) || (pkttype == PKTBYTE_SECSUBKEY);
if( fSubkey ) {
/* Subkey */
pgpAssert( IsntNull( parent ) );
pgpAssert( OBJISTOPKEY( parent ) );
} else {
pgpAssert( IsNull( parent ) );
}
/* Find the matching key structure */
(void)pgpGetKeyByKeyID( kdb, &keyID, TRUE, TRUE, &key);
fDummy = IsntNull( key ) && pgpKeyDBObjIsDummy( key );
if( IsntNull( key ) && !fDummy ) {
if( OBJISTOPKEY(key) == fSubkey )
{
/* Previous key and this key disagree on subkey-ness. Use prev. */
/* Note that if prev is a subkey we will reject new userids
* as they can't go below subkeys.
*/
key->objflags &= ~kPGPKeyDBObjFlags_Deleted;
return key;
}
/* Compare key with our data */
kdata = pgpFetchObject( key, &kdatalen );
if( !sObjectMatchesBuffer( key, buf, len ) )
{
/* Here what we are importing doesn't exactly match what we have */
/* If previous was deleted, replace with new data */
if( pgpKeyDBObjIsDeleted( key ) )
{
key->objflags &= ~kPGPKeyDBObjFlags_Deleted;
goto fillin;
}
/* Else could just be a sec/pub disagreement */
if( pkttype == PKTBYTE_TYPE(kdata[0]) )
{
/* No, that's not it, ignore new one */
return key;
}
/* Here we disagree on sec/pub, see if they are otherwise same */
if( fSecret )
{
pgpAssert( PKTBYTE_TYPE(kdata[0]) == PKTBYTE_PUBKEY ||
PKTBYTE_TYPE(kdata[0]) == PKTBYTE_PUBSUBKEY );
if( !sConsistentPubAndSec( kdata, kdatalen, buf, len, &vbug ) )
{
/* Inconsistent, ignore new data */
return key;
}
if( trusted && vbug )
{
kinfo = pgpKeyToKeyInfo( key );
KEYSETVERSIONBUG( kinfo );
}
/* New sec data must replace pub */
kinfo = pgpKeyToKeyInfo( key );
kinfo->data = pgpNewObjData( kdb, buf, len );
KEYSETSEC( kinfo );
} else {
pgpAssert( !fSecret );
pgpAssert( PKTBYTE_TYPE(kdata[0]) == PKTBYTE_SECKEY ||
PKTBYTE_TYPE(kdata[0]) == PKTBYTE_SECSUBKEY );
if( !sConsistentPubAndSec( buf, len, kdata, kdatalen, &vbug ) )
{
/* Inconsistent, ignore new data */
return key;
}
/* New pub data matches sec; record evidence of version bug */
if( trusted && vbug )
{
kinfo = pgpKeyToKeyInfo( key );
KEYSETVERSIONBUG( kinfo );
}
}
} else {
/* Match OK on key */
key->objflags &= ~kPGPKeyDBObjFlags_Deleted;
}
return key;
}
if( fDummy ) {
/* Key was a keyid only key */
if( fSubkey && OBJISTOPKEY( key ) ) {
/* Here we had a dummy top level key which turns out
* to be a subkey (can't happen unless subkeys sign) */
/* Move it to proper position and mark as subkey. */
pgpUnlinkKey( key, kdb );
pgpLinkChild( key, parent );
key->objflags &= ~kPGPKeyDBObjType_Key;
key->objflags |= kPGPKeyDBObjType_SubKey;
}
key->objflags &= ~kPGPKeyDBObjFlags_Dummy;
kinfo = pgpKeyToKeyInfo( key );
/* Fix disagreement on pkalg for dummy key */
if( kinfo->pkalg == kPGPPublicKeyAlgorithm_RSA &&
pkalg == kPGPPublicKeyAlgorithm_RSASignOnly )
kinfo->pkalg = kPGPPublicKeyAlgorithm_RSASignOnly;
pgpAssert( kinfo->pkalg == pkalg );
pgpAssert( pgpMemoryEqual( kinfo->keyID, keyIDBytes,
sizeof(keyIDBytes) ) );
}
if( IsNull( key ) ) {
key = fSubkey ? sNewSubKey( kdb ) : sNewKey( kdb );
if ( key == NULL )
{
err = kPGPError_OutOfMemory;
goto error;
}
if( fSubkey ) {
pgpLinkChild( key, parent );
} else {
pgpLinkKey( key, kdb );
}
kinfo = pgpKeyToKeyInfo( key );
kinfo->pkalg = pkalg;
pgpCopyMemory( keyIDBytes, kinfo->keyID, sizeof(keyIDBytes) );
pgpLinkKeyToTree( key, kdb );
}
fillin:
/* Fill in key data */
kinfo = pgpKeyToKeyInfo( key );
kinfo->fp20n = fp20n[0];
kinfo->creationtime = tstamp;
kinfo->validityperiod = validity;
kinfo->keybits = keybits;
kinfo->trust = 0;
if (v3)
KEYSETV3(kinfo);
else
KEYCLEARV3(kinfo);
if( fSecret )
KEYSETSEC(kinfo);
else
KEYCLEARSEC(kinfo);
kinfo->data = pgpNewObjData( kdb, buf, len );
return key;
error:
*outerr = err;
return NULL;
}
PGPKeyDBObj *
pgpAddUserID( PGPInt32 pkttype, PGPByte const *buf, PGPSize len,
PGPKeyDB *kdb, PGPKeyDBObj *parent, PGPError *outerr )
{
PGPKeyDBObj * name;
PGPUserIDInfo * uinfo;
PGPError err;
(void)pkttype;
pgpAssert( IsntNull( parent ) );
if( !OBJISTOPKEY( parent ) )
/* Can't add it */
return NULL;
/* Find the matching name structure */
name = pgpFindMatchingChild( parent, buf, len );
if( IsntNull( name ) ) {
/* Got a match */
if( name->objflags & kPGPKeyDBObjFlags_Deleted )
{
/* Bring back to life at end of list */
name->objflags &= ~kPGPKeyDBObjFlags_Deleted;
pgpUnlinkChild( name, parent );
pgpLinkChild( name, parent );
}
return name;
} else {
name = sNewUserID( kdb );
if ( name == NULL )
{
err = kPGPError_OutOfMemory;
goto error;
}
uinfo = pgpUserIDToUserIDInfo( name );
uinfo->validity = PGP_NEWTRUST_UNDEFINED;
uinfo->confidence = PGP_NEWTRUST_UNDEFINED;
pgpLinkChild( name, parent );
}
uinfo = pgpUserIDToUserIDInfo( name );
if( pkttype == PKTBYTE_ATTRIBUTE )
NAMESETATTR(uinfo);
uinfo->data = pgpNewObjData( kdb, buf, len );
return name;
error:
*outerr = err;
return NULL;
}
PGPKeyDBObj *
pgpAddSig( PGPInt32 pkttype, PGPByte const *buf, PGPSize len,
PGPKeyDB *kdb, PGPKeyDBObj *parent, PGPError *error )
{
PGPKeyDBObj * sig;
PGPKeyDBObj * key;
PGPKeyDBObj * tsig;
PGPKeyInfo * kinfo;
PGPSigInfo * sinfo;
PGPByte pkalg;
PGPByte vpkalg;
PGPByte keyidbytes[8];
PGPByte x509subjectkeyidbytes[8];
PGPUInt32 tstamp;
PGPUInt32 sigvalidity;
PGPByte type;
PGPByte hashalg;
PGPSize extralen;
PGPByte version;
PGPBoolean exportable;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -