📄 pgpkeyadd.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
Add keydb objects to databases
$Id: pgpKeyAdd.c,v 1.82 2002/08/06 20:11:00 dallen Exp $
____________________________________________________________________________*/
#include "pgpConfig.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "pgpDebug.h"
#include "pgpPktByte.h"
#include "pgpKeyPriv.h"
#include "pgpHash.h"
#include "pgpKeySpec.h"
#include "pgpMem.h"
#include "pgpEnv.h"
#include "pgpErrors.h"
#include "pgpPubKey.h"
#include "pgpFile.h"
#include "pgpMakeSig.h"
#include "pgpSigSpec.h"
#include "pgpContext.h"
#include "pgpTrustPriv.h"
#include "pgpX509Priv.h"
#ifndef NULL
#define NULL 0
#endif
/* Simple link manipulations */
/* Link key last in keydb */
static void
pgpLinkKey( PGPKeyDBObj *key, PGPKeyDB *kdb )
{
PGPKeyDBObj *lastkey;
if( IsNull( kdb->firstKeyInDB ) )
{
kdb->firstKeyInDB = key;
} else {
lastkey = kdb->lastKeyInDB;;
if( IsNull( lastkey ) )
lastkey = kdb->firstKeyInDB;
while( IsntNull( lastkey->next ) )
lastkey = lastkey->next;
lastkey->next = key;
}
key->next = NULL;
key->up = (PGPKeyDBObj *)kdb; /* Overload up pointer as db pointer */
kdb->lastKeyInDB = key;
}
static void
pgpUnlinkKey( PGPKeyDBObj *key, PGPKeyDB *kdb )
{
PGPKeyDBObj *prev;
if( kdb->firstKeyInDB == key )
{
kdb->firstKeyInDB = key->next;
key->next = NULL;
return;
}
for( prev = kdb->firstKeyInDB; IsntNull(prev->next); prev=prev->next )
{
if( prev->next == key )
{
prev->next = key->next;
key->next = NULL;
return;
}
}
pgpAssert( 0 );
}
/* link at end; put userids before subkeys, sigs before them */
static void
pgpLinkChild( PGPKeyDBObj *child, PGPKeyDBObj *parent )
{
PGPKeyDBObj **pnext;
PGPBoolean isUserID;
PGPBoolean isSig;
/* Put sigs first, then userids, then subkeys */
isUserID = pgpObjectType(child) == RINGTYPE_USERID;
isSig = pgpObjectType(child) == RINGTYPE_SIG;
/* pnext points at pointer to next sibling */
for( pnext = &parent->down; IsntNull( *pnext ); pnext = &((*pnext)->next) )
{
PGPInt32 nexttype = pgpObjectType(*pnext);
if( isSig && nexttype!=RINGTYPE_SIG )
break;
if( isUserID && nexttype!=RINGTYPE_SIG && nexttype!=RINGTYPE_USERID)
break;
}
child->next = *pnext;
*pnext = child;
child->up = parent;
}
static void
pgpUnlinkChild( PGPKeyDBObj *child, PGPKeyDBObj *parent )
{
PGPKeyDBObj *prev;
if( parent->down == child )
{
parent->down = child->next;
child->next = NULL;
child->up = NULL;
return;
}
for( prev = parent->down; IsntNull(prev->next); prev=prev->next )
{
if( prev->next == child )
{
prev->next = child->next;
child->next = NULL;
child->up = NULL;
return;
}
}
pgpAssert(0);
}
static PGPKeyDBObj *
sNewObj( PGPKeyDB *kdb, PGPSize infosize )
{
PGPKeyDBObjInfo *info;
PGPKeyDBObj *obj;
MemPool cutback;
cutback = kdb->objPool;
obj = memPoolAlloc( &kdb->objPool, sizeof(PGPKeyDBObj), sizeof (void *) );
if (IsNull( obj ) )
goto outofmem;
info = memPoolAlloc( &kdb->objPool, infosize, sizeof (void *) );
if (IsNull( info ) )
goto outofmem;
pgpClearMemory( obj, sizeof(*obj) );
pgpClearMemory( info, infosize );
obj->magic = kPGPKeyDBObjMagic;
obj->idinfo.info = info;
return obj;
outofmem:
memPoolCutBack( &kdb->objPool, &cutback );
pgpKeyDBSetError( kdb, kPGPError_OutOfMemory );
return NULL;
}
static PGPKeyDBObj *
sNewKey( PGPKeyDB *kdb )
{
PGPKeyDBObj *key;
key = sNewObj( kdb, sizeof(PGPKeyInfo) );
if( IsNull( key ) )
return NULL;
key->objflags = kPGPKeyDBObjType_Key;
return key;
}
static PGPKeyDBObj *
sNewUserID( PGPKeyDB *kdb )
{
PGPKeyDBObj *userid;
userid = sNewObj( kdb, sizeof(PGPUserIDInfo) );
if( IsNull( userid ) )
return NULL;
userid->objflags = kPGPKeyDBObjType_UserID;
return userid;
}
static PGPKeyDBObj *
sNewSig( PGPKeyDB *kdb )
{
PGPKeyDBObj *sig;
sig = sNewObj( kdb, sizeof(PGPSigInfo) );
if( IsNull( sig ) )
return NULL;
sig->objflags = kPGPKeyDBObjType_Signature;
return sig;
}
static PGPKeyDBObj *
sNewSubKey( PGPKeyDB *kdb )
{
PGPKeyDBObj *subkey;
subkey = sNewObj( kdb, sizeof(PGPKeyInfo) );
if( IsNull( subkey ) )
return NULL;
subkey->objflags = kPGPKeyDBObjType_SubKey;
return subkey;
}
static PGPKeyDBObj *
sNewCRL( PGPKeyDB *kdb )
{
PGPKeyDBObj *crl;
crl = sNewObj( kdb, sizeof(PGPCRLInfo) );
if( IsNull( crl ) )
return NULL;
crl->objflags = kPGPKeyDBObjType_CRL;
return crl;
}
static PGPKeyDBObj *
sNewUnknown( PGPKeyDB *kdb )
{
PGPKeyDBObj *unk;
unk = sNewObj( kdb, sizeof(PGPUnkInfo) );
if( IsNull( unk ) )
return NULL;
return unk;
}
/*
* X.509 certs require some special handling.
*
* Ordinary PGP signatures are linked to their issuing key by the
* keyid field (and algorithm byte). We maintain the sigsby/nextby
* linked list which links keys to the signatures they have issued.
* When we add a new signature, we look for a key with that keyid,
* and create a Dummy one if not found. We then add the sig to the
* sigsby list for that key. When we add a new key, if it already
* exists nothing happens; if a Dummy version exists then its sigsby
* list already points at the signatures which have been issued by this
* key, so we clear the Dummy flag; and if there is no key with this
* keyid, that means that there have been no signatures issued by this
* key, so we just create a new key object and its sigsby list is
* empty.
*
* X.509 certificates are linked to their issuing certificate (note,
* certificate not key) by the Issuer Name field. This is a
* structured list of textual subfields like Common Name,
* Organizational Unit, etc. This introduces several problems for us.
* First, we want to look for keys by keyid, not a set of text fields.
* Second, when we first read an X.509 CA key, we may not know its
* Issuer Name field, not until we read its self-signed CA
* certificate. Theoretically that could happen at some later time.
* Third, if we create a dummy key to represent the signer for X.509
* certificates, this would probably be a different dummy key than the
* one created as a dummy for PGP keys.
*
* To handle this, we look up X.509 keys by creating a keyid-like
* field which is the hash of the Issuer Name. Every X.509 issuer has
* two key object entries, the real one, and an X.509 Dummy whose
* keyid is this hash. The X.509 Dummy is tagged as such, and
* overloads its data field to point at the X.509 cert on the real
* key. (Theoretically, an X.509 issuer could have more than one
* X.509 Dummy associated with it, if it had more than one cert with
* different Issuer Names.)
*
* The basic mechanism of the X.509 Dummy solves our problems, as
* follows. When we import an X.509 certificate, we hash the Issuer
* Name to produce the X.509 Dummy keyid and look up a key with that
* ID. (We also use a fake algorithm byte of 0x80.) If found, we
* then look at its data field to see if there is a real key that
* corresponds, and use that if so. (This last step is done in
* GetKeyByKeyID.) Otherwise we use the X.509 Dummy for the by field
* of the sig, creating one if necessary. This ensures that all X.509
* certs issued by the same key will point at the same X.509 Dummy if
* we don't have the issuing cert.
*
* Furthermore, when we import an X.509 certificate, the Subject Name
* of the cert would be the Issuer Name used if the parent key issues
* any certs of its own. (In the case of a self-signed CA cert,
* the Subject Name and Issuer Name are the same.) So in addition
* to the processing above, we also use the Subject Name of the cert
* to look for and/or create an X.509 Dummy corresponding to the parent
* key. Keep in mind, this is for use of the parent key as an X.509
* cert issuer. The previous paragraph was with respect to finding
* the key which issued this X.509 cert, this describes mechanism to
* find certs issued by this X.509 key.
*
* Using the Issuer Name we create an X.509 Dummy keyid and look up or
* create an X.509 Dummy key. If found, we set its data field to
* point at the cert on the issuing key. Further, we move any keys
* from the X.509 Dummy's sigsby list to the sigsby list of the parent
* key, and change those sigs' by pointers to point to the parent key.
* This way, once we have read the X.509 issuing key's certificate,
* the issued certificates point at the issuing key.
*
*/
/* Find fake X.509 keyid as hash of issuer and subject names */
/* Also return flag saying whether cert has a CRL distribution point */
static PGPError
sX509KeyIDBytes( PGPKeyDB *kdb, PGPByte const *buf, PGPSize len,
PGPBoolean *hasdpoint, PGPByte issuerkeyidbytes[8],
PGPByte subjectkeyidbytes[8])
{
PGPContextRef context;
PGPASN_XTBSCertificate *xtbscert;
PGPByte const * certbuf;
PGPSize certlen;
PGPByte const * issuername;
PGPSize issuerlen;
PGPByte const * subjectname;
PGPSize subjectlen;
PGPByte const * dpoint;
PGPByte hash[20];
PGPError err;
(void) len;
if( IsntNull( hasdpoint ) )
*hasdpoint = FALSE;
context = PGPPeekKeyDBContext( kdb );
certbuf = pgpSigFindNAISubSubpacket (buf,
SIGSUBSUB_X509, 0, &certlen, NULL, NULL, NULL, NULL);
pgpAssert (IsntNull( certbuf ) );
/* Skip type, version bytes */
pgpAssert (certbuf[0] == SIGSUBSUB_X509);
certbuf += 3;
certlen -= 3;
/* Find issuer name in cert */
err = pgpX509BufferToXTBSCert( context, certbuf, certlen, &xtbscert);
if( IsPGPError( err ) )
return err;
issuername = xtbscert->issuer.val;
issuerlen = xtbscert->issuer.len;
subjectname = xtbscert->subject.val;
subjectlen = xtbscert->subject.len;
pgpFingerprint20HashBuf(context, issuername, issuerlen, hash);
pgpCopyMemory( hash + sizeof(hash) - 8, issuerkeyidbytes, 8 );
pgpFingerprint20HashBuf(context, subjectname, subjectlen, hash);
pgpCopyMemory( hash + sizeof(hash) - 8, subjectkeyidbytes, 8 );
if( IsntNull( hasdpoint ) )
{
dpoint = pgpX509XTBSCertToDistPoint( xtbscert, NULL );
if( dpoint != NULL ) {
*hasdpoint = TRUE;
PGPFreeData( (PGPByte *)dpoint );
}
}
pgpX509FreeXTBSCert( context, xtbscert );
return kPGPError_NoErr;
}
/* Having processed an X.509 sig, create or check for a dummy X509 key object
* which will represent the "X.509 key id" of the key. That is the
* low 64 bits of the hash of the subject name.
*/
static PGPError
sFixupX509ParentKey( PGPKeyDB *kdb, PGPKeyDBObj *sig,
PGPByte x509subjectkeyidbytes[8] )
{
PGPKeyDBObj * key;
PGPKeyDBObj * x509key;
PGPKeyInfo * kinfo;
PGPKeyInfo * x509kinfo;
PGPSigInfo * sinfo;
PGPSigInfo * lastsiginfo = NULL;
PGPKeyID keyID;
PGPByte pkalg;
key = sig;
while( !OBJISTOPKEY( key ) )
key = key->up;
kinfo = pgpKeyToKeyInfo( key );
/* Look up X.509 dummy key paired with this one */
pkalg = 0x80;
pgpNewKeyIDFromRawData( x509subjectkeyidbytes, pkalg, 8, &keyID );
pgpGetKeyByKeyID( kdb, &keyID, TRUE, TRUE, &x509key );
if( IsntNull( x509key ) )
{
/* If we have a real key this will already be pointing at it */
if( !pgpKeyDBObjIsX509Dummy( x509key ) )
{
/*
* Ideally, at this point x509key is the same as key,
* and we are done. It means that our key already has its
* paired dummy x509 key. Conceivably it could be a
* different key, though. That would mean that we have *
* two certs on different keys with the same subject name.
* This is unfortunate if one were to issue an X.509 certs
* itself, since there would be no way to know which one
* was the signer of such a cert. We won't worry too much
* about that since it shouldn't happen in X.509 land and
* it won't cause any trouble if it doesn't happen.
*/
/* pgpAssert( x509key == key ); */
return kPGPError_NoErr;
}
/*
* Here we have a dummy x509 entry. This means that we have read
* one or more X.509 certs which used this key as the signer.
* They created this dummy entry and pointed their "by" pointers
* to it. Now we must point this dummy to our real key, and
* move those sigs' "by" pointers to the real key too.
*/
/* Set paired data pointer */
x509kinfo = pgpKeyToKeyInfo( x509key );
pgpAssert( IsNull( x509kinfo->data ) );
x509kinfo->data = (void *)sig;
/* Fix "by" pointers in sigs */
pgpAssert( IsntNull( x509kinfo->sigsby ) );
for (sig = x509kinfo->sigsby; IsntNull(sig); sig = sinfo->nextby) {
pgpAssert( OBJISSIG( sig ) );
sinfo = pgpSigToSigInfo( sig );
sinfo->by = key;
lastsiginfo = sinfo;
}
/* Move sigs from x509kinfo->sigsby list to kinfo->sigsby list */
lastsiginfo->nextby = kinfo->sigsby;
kinfo->sigsby = x509kinfo->sigsby;
x509kinfo->sigsby = NULL;
} else {
/*
* Here we need to create a dummy X.509 key entry which will
* be paired with our key and hold the alternate X509 keyid
* for our key. */
x509key = sNewKey( kdb );
if( IsNull( key ) )
return kPGPError_OutOfMemory;
x509kinfo = pgpKeyToKeyInfo( x509key );
pgpCopyMemory( x509subjectkeyidbytes, x509kinfo->keyID, 8 );
x509kinfo->pkalg = pkalg;
x509kinfo->data = (void *)sig;
x509key->objflags |= kPGPKeyDBObjFlags_X509 | kPGPKeyDBObjFlags_Dummy;
pgpLinkKey( x509key, kdb );
pgpLinkKeyToTree( x509key, kdb );
}
return kPGPError_NoErr;
}
/*
* Find paired CA key in another DB. Will return X509 dummy unless a
* "real" CA key exists in that DB.
*/
PGPKeyDBObj *
pgpFindPairedX509Key( PGPKeyDBObj *cakey, PGPKeyDBRef kdb )
{
PGPKeyDBObj *x509key;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -