📄 pgpkeyadd.c
字号:
* set of keydb objects. Then self-sign the pubkey. Return the
* key object.
*/
PGPKeyDBObj *
pgpCreateKeypair (PGPEnv const *env, PGPKeyDB *db, PGPSecKey *seckey,
PGPKeySpec *keyspec, char const *name, size_t namelen,
PGPKeySet const *adkset, PGPByte adkclass,
PGPKeySet const *rakset, PGPByte rakclass,
PGPByte const *passphrase, PGPSize pplen, PGPBoolean hashedPhrase,
PGPError *error)
{
PGPKeyDBObj *keyobj=NULL, *nameobj;
PGPKeyDBObj *tmpkey;
PGPKeyInfo *kinfo;
PGPSigSpec *sigspec = NULL;
PGPKeyIter *rakIter = NULL;
PGPKeyIter *adkIter = NULL;
PGPByte const *prefAlg;
PGPSize prefAlgLength;
PGPByte const *prefKeyServ;
PGPSize prefKeyServLength;
PGPUInt32 keyFlags, keyServPrefs;
PGPBoolean fKeyFlags, fKeyServPrefs;
PGPUInt16 validity;
PGPUInt32 nkeys;
PGPError err;
PGPUInt32 i;
PGPBoolean keyv4;
PGPBoolean secret = TRUE;
PGPPubKey *pubkey = NULL;
PGPByte pkalg;
pgpAssert( error );
*error = kPGPError_NoErr;
#define CHECKRETVAL(val, err) if (val) { *error = err; goto cleanup; }
/* SECRET KEY stuff */
keyv4 = pgpKeySpecVersion (keyspec) > PGPVERSION_3;
pkalg = seckey->pkAlg;
if( pgpSecKeyOnToken(seckey) )
{
secret = FALSE;
pubkey = pgpSecKeyPubkey(seckey);
}
keyobj = pgpCreateKey (db, NULL, secret, pubkey, (secret?seckey:NULL),
keyspec, pkalg);
CHECKRETVAL (!keyobj, kPGPError_OutOfMemory);
pgpAssert(OBJISKEY(keyobj));
kinfo = pgpKeyToKeyInfo( keyobj );
pgpSecKeySetKeyID( seckey, kinfo->keyID );
if( !secret )
{
pgpPubKeySetKeyID( pubkey, kinfo->keyID );
pgpKeyOnToken( keyobj, NULL );
}
nameobj = pgpCreateUserID (db, keyobj, (PGPByte *) name, namelen);
CHECKRETVAL (!nameobj, kPGPError_OutOfMemory);
/* Self-Sign the new pubkey */
if (pgpKeyAlgUse(pgpPkalgByNumber(pkalg)) & PGP_PKUSE_SIGN)
{
sigspec = pgpSigSpecCreate (env, keyobj, PGP_SIGTYPE_KEY_GENERIC);
CHECKRETVAL (!sigspec, kPGPError_OutOfMemory);
pgpSigSpecSetPassphrase( sigspec, passphrase, pplen, hashedPhrase );
if (keyv4)
{
/* New keys self-sign with special info! */
static PGPByte defaultPrefAlg[] = {kPGPCipherAlgorithm_CAST5,
kPGPCipherAlgorithm_IDEA,
kPGPCipherAlgorithm_3DES};
PGPByte flagbuf[4];
prefAlg = pgpKeySpecPrefAlgs (keyspec, &prefAlgLength);
if( IsntNull( prefAlg ) )
{
pgpSigSpecSetPrefAlgs (sigspec, 0, prefAlg, prefAlgLength);
} else {
pgpSigSpecSetPrefAlgs (sigspec, 0, defaultPrefAlg,
sizeof(defaultPrefAlg));
}
prefKeyServ = pgpKeySpecPrefKeyserv (keyspec, &prefKeyServLength);
if( IsntNull( prefKeyServ ) )
{
pgpSigSpecSetPrefKeyServ (sigspec, 0, prefKeyServ,
prefKeyServLength);
}
keyFlags = pgpKeySpecKeyflags (keyspec, &fKeyFlags);
if( fKeyFlags )
{
for( i=0; i<sizeof(flagbuf); ++i )
flagbuf[i] = (PGPByte)(keyFlags >> (i*8));
pgpSigSpecSetKeyFlags( sigspec, 0, flagbuf, sizeof(flagbuf) );
}
keyServPrefs = pgpKeySpecKeyservPrefs (keyspec, &fKeyServPrefs);
if( fKeyServPrefs )
{
for( i=0; i<sizeof(flagbuf); ++i )
flagbuf[i] = (PGPByte)(keyServPrefs >> (i*8));
pgpSigSpecSetKeyServPrefs( sigspec, 0, flagbuf,
sizeof(flagbuf) );
}
pgpSigSpecSetVersion (sigspec, PGPVERSION_4);
pgpSigSpecSetPrimaryUserID (sigspec, 0, TRUE);
if ((validity=pgpKeySpecValidity (keyspec)) != 0)
{
pgpSigSpecSetKeyExpiration (sigspec, 0,
(PGPUInt32)validity*24*60*60);
kinfo->validityperiod = validity;
}
/* Add any additional decryption packets requested */
if (IsntNull (adkset) &&
((void)PGPCountKeys((PGPKeySet *)adkset,&nkeys), nkeys>0))
{
if( IsPGPError( err = PGPNewKeyIterFromKeySet (
(PGPKeySet *)adkset, &adkIter ) ) )
{
*error = err;
goto cleanup;
}
while( IsntPGPError( PGPKeyIterNextKeyDBObj( adkIter,
kPGPKeyDBObjType_Key, &tmpkey ) ) )
{
PGPByte adinfo[22];
kinfo = pgpKeyToKeyInfo( tmpkey );
adinfo[0] = adkclass;
adinfo[1] = kinfo->pkalg;
pgpKeyFingerprint20( tmpkey, adinfo+2 );
*error = pgpSigSpecSetAdditionalRecipientRequest (sigspec,
0, adinfo, sizeof(adinfo) );
CHECKRETVAL (*error, *error);
}
PGPFreeKeyIter (adkIter);
adkIter = NULL;
}
}
*error = pgpSignObject( nameobj, sigspec );
if (IsntPGPError(*error) && keyv4 && IsntNull (rakset) &&
((void)PGPCountKeys((PGPKeySet *)rakset,&nkeys), nkeys>0))
{
/* Add any Revocation Authorization Keys requested */
/* These go in a separate, irrevocable signature on the key */
pgpSigSpecDestroy (sigspec);
sigspec = pgpSigSpecCreate (env, keyobj, PGP_SIGTYPE_KEY_PROPERTY);
CHECKRETVAL (!sigspec, kPGPError_OutOfMemory);
pgpSigSpecSetPassphrase( sigspec, passphrase, pplen, hashedPhrase);
if( IsPGPError( err = PGPNewKeyIterFromKeySet (
(PGPKeySet *)rakset, &rakIter ) ) )
{
*error = err;
goto cleanup;
}
while( IsntPGPError( PGPKeyIterNextKeyDBObj( rakIter,
kPGPKeyDBObjType_Key, &tmpkey ) ) )
{
PGPByte krinfo[22];
kinfo = pgpKeyToKeyInfo( tmpkey );
/* Note that rakclass must have 0x80 set to be effective */
krinfo[0] = rakclass;
krinfo[1] = kinfo->pkalg;
pgpKeyFingerprint20 ( tmpkey, krinfo+2 );
*error = pgpSigSpecSetRevocationKey (sigspec, 0, krinfo,
sizeof(krinfo) );
CHECKRETVAL (*error, *error);
}
PGPFreeKeyIter (rakIter);
rakIter = NULL;
/* Make this signature non-revocable */
pgpSigSpecSetRevocable (sigspec, 0, FALSE);
*error = pgpSignObject (keyobj, sigspec);
}
}
/* This sets both key and name trust */
pgpKeySetAxiomatic(keyobj);
pgpKeyDBChanged( db, TRUE );
cleanup:
if (pubkey)
pgpPubKeyDestroy (pubkey);
if (sigspec)
pgpSigSpecDestroy (sigspec);
if (rakIter)
PGPFreeKeyIter( rakIter );
if (adkIter)
PGPFreeKeyIter( adkIter );
return keyobj;
}
/*
* Given a (top level) key, a keyspec, and some other information,
* create a subkey keydb object and put it under the keydb.
* Then sign the pubkey using the master signature key.
* seckey is the secret key coresponding to the master signature key,
* subseckey is the secret key to be used for creating the new subkey.
*/
PGPKeyDBObj *
pgpCreateSubkeypair (PGPKeyDBObj *keyobj, PGPEnv const *env,
PGPSecKey *subseckey, PGPKeySpec *keyspec,
PGPByte const *passphrase, PGPSize pplen, PGPBoolean hashedPhrase,
PGPError *error)
{
PGPKeyDB *db = PGPPeekKeyDBObjKeyDB( keyobj );
PGPKeyDBObj *subkeyobj = NULL;
PGPSigSpec *sigspec = NULL;
PGPKeyInfo *kinfo;
PGPUInt16 validity;
PGPUInt32 keyFlags;
PGPBoolean fKeyFlags;
PGPUInt32 i;
PGPBoolean secret = TRUE;
PGPPubKey *subpubkey = NULL;
PGPByte pkalg;
pgpAssert( error );
*error = kPGPError_NoErr;
/*
* All subkeys are V4.
*/
pgpKeySpecSetVersion (keyspec, PGPVERSION_4);
pkalg = subseckey->pkAlg;
if( pgpSecKeyOnToken(subseckey) )
{
secret = FALSE;
subpubkey = pgpSecKeyPubkey(subseckey);
}
/* Create the subkey object on the secret keyring */
subkeyobj = pgpCreateKey (db, keyobj, secret, subpubkey,
(secret?subseckey:NULL), keyspec, pkalg);
if (!subkeyobj)
{
*error = kPGPError_OutOfMemory;
return NULL;
}
kinfo = pgpKeyToKeyInfo( subkeyobj );
if( !secret )
{
pgpPubKeySetKeyID( subpubkey, kinfo->keyID );
pgpKeyOnToken( subkeyobj, NULL );
}
pgpSecKeySetKeyID( subseckey, kinfo->keyID );
/* Sign the encryption key with the master signature key */
sigspec = pgpSigSpecCreate (env, keyobj, PGP_SIGTYPE_KEY_SUBKEY);
if (!sigspec)
{
*error = kPGPError_OutOfMemory;
return NULL;
}
pgpSigSpecSetPassphrase( sigspec, passphrase, pplen, hashedPhrase );
/* New keys self-sign with special info */
if ((validity=pgpKeySpecValidity (keyspec)) != 0)
{
pgpSigSpecSetKeyExpiration (sigspec, 0,
(PGPUInt32)validity*24*3600);
kinfo->validityperiod = validity;
}
keyFlags = pgpKeySpecKeyflags( keyspec, &fKeyFlags );
if( fKeyFlags )
{
PGPByte flagbuf[4];
for( i=0; i<sizeof(flagbuf); ++i )
flagbuf[i] = (PGPByte)(keyFlags >> (i*8));
pgpSigSpecSetKeyFlags( sigspec, 0, flagbuf, sizeof(flagbuf) );
}
*error = pgpSignObject ( subkeyobj, sigspec );
if (*error)
goto cleanup;
pgpKeySetAxiomatic(subkeyobj);
pgpKeyDBChanged( db, TRUE );
cleanup:
if (subpubkey)
pgpPubKeyDestroy (subpubkey);
if (sigspec)
pgpSigSpecDestroy (sigspec);
return subkeyobj; /* success */
}
/*
* Signs an object (and its parents); then deposits the new signature
* object in place on the set.
*/
PGPError
pgpSignObject(PGPKeyDBObj *obj, PGPSigSpec *spec)
{
PGPKeyDB * kdb;
PGPByte * sig;
PGPInt32 siglen;
PGPKeyDBObj * sigobj = NULL;
PGPContextRef cdkContext;
PGPSigInfo * sinfo;
kdb = PGPPeekKeyDBObjKeyDB( obj );
cdkContext = PGPPeekKeyDBContext( kdb );
/*
* Force signatures with newer-than-RSA keys to use version 4,
* and also if the hash is newer than those supported by PGP 5.0.
* A bug in PGP 5.0 won't let it load keyrings using version 2.6 sigs
* which have a hash not recognized by it.
* The exception is revocation sigs on top-level keys. A different
* bug in PGP 5.0 won't let it validate V4 sigs on top-level keys.
* The only sigs it tries to recognize on top-level keys are revocation
* sigs. So those we leave as V3.
*
* Now we are also using V4 signatures when signing with an RSA key on
* a non-RSA key. There is no backwards compatibility issue there
* so we'd rather move forward with the V4 signatures consistently.
*/
if( pgpSigSpecVersion (spec) == PGPVERSION_3 ) {
PGPKeyDBObj *signkey = pgpSigSpecSeckey (spec);
PGPByte hashtype = pgpSigSpecHashtype (spec);
PGPByte sigtype = pgpSigSpecSigType (spec);
PGPKeyInfo *kinfo;
PGPKeyDBObj *topobj = obj;
while (!OBJISTOPKEY (topobj))
topobj = topobj->up;
pgpAssert (OBJISTOPKEY(topobj));
kinfo = pgpKeyToKeyInfo( topobj );
if( ! (sigtype == PGP_SIGTYPE_KEY_REVOKE && OBJISTOPKEY(obj)) ) {
PGPInt32 pkalg;
pgpGetKeyNumber( signkey, kPGPKeyProperty_AlgorithmID, &pkalg );
if( pkalg > kPGPPublicKeyAlgorithm_RSA
|| kinfo->pkalg > kPGPPublicKeyAlgorithm_RSA
|| hashtype > kPGPHashAlgorithm_RIPEMD160) {
pgpSigSpecSetVersion( spec, PGPVERSION_4 );
}
}
}
siglen = pgpSignObj (obj, spec, &sig);
if (siglen < 0)
return (PGPError)siglen;
if (siglen == 0)
{
pgpContextMemFree( cdkContext, sig);
return kPGPError_OutOfMemory;
}
sigobj = pgpCreateSig (kdb, obj, sig, siglen);
pgpContextMemFree( cdkContext, sig);
if( IsNull( sigobj ) )
return pgpKeyDBError( kdb );
sinfo = pgpSigToSigInfo( sigobj );
sinfo->trust = PGP_SIGTRUSTF_CHECKED_TRIED | kPGPKeyTrust_Complete;
return sigobj ? kPGPError_NoErr : kPGPError_OutOfMemory;
}
/*
* Create a new public key in a keydb. secret is true for pub/sec key
* pairs. If parent is non-null, this is a subkey of that parent.
* If secret is set, skey is used, else pkey is used.
*/
PGPKeyDBObj *
pgpCreateKey(PGPKeyDB *db, PGPKeyDBObj *parent, PGPBoolean secret,
PGPPubKey const *pkey, PGPSecKey const *skey, PGPKeySpec const *ks,
PGPByte pkalg)
{
PGPContextRef context;
PGPKeyDBObj *obj;
PGPByte *pktbuf;
PGPSize len, prefixlen, headerlen;
PGPError err;
PGPByte pkttype;
if( secret )
pkttype = parent ? PKTBYTE_SECSUBKEY : PKTBYTE_SECKEY;
else
pkttype = parent ? PKTBYTE_PUBSUBKEY : PKTBYTE_PUBKEY;
pgpAssert( secret ? IsNull(pkey) : IsNull(skey) );
pgpAssert( secret ? IsntNull(skey) : IsntNull(pkey) );
pkttype = PKTBYTE_BUILD( pkttype, 1 );
/* Calculate packet size */
prefixlen = pgpKeyBufferLength(ks, pkalg);
len = prefixlen + (secret ? pgpSecKeyBufferLength(skey)
: pgpPubKeyBufferLength(pkey) );
headerlen = pgpPktHeaderLen( pkttype, len );
len += headerlen;
if (len >= PGPOBJ_MAXSIZE) {
pgpKeyDBSetError( db, kPGPError_TroubleKeyTooBig);
return NULL;
}
/* Allocate space */
context = PGPPeekKeyDBContext( db );
pktbuf = pgpContextMemAlloc( context, len, 0 );
if( IsNull(pktbuf) )
{
pgpKeyDBSetError( db, kPGPError_OutOfMemory );
return NULL;
}
/* Fill buffer */
pgpPktHeaderPut( pktbuf, pkttype, len-headerlen );
pgpKeyToBuffer(pktbuf+headerlen, ks, pkalg);
if( secret )
pgpSecKeyToBuffer(skey, pktbuf+headerlen+prefixlen);
else
pgpPubKeyToBuffer(pkey, pktbuf+headerlen+prefixlen);
/* Add to keyring (makes a copy of the data buffer) */
obj = pgpAddObject( pktbuf, len, db, parent, TRUE, &err );
PGPFreeData( pktbuf );
return obj;
}
/*
* Change the data associated with a secret key.
*/
PGPError
pgpUpdateSecKeyData( PGPKeyDBObj *key, PGPSecKey const *skey )
{
PGPContextRef context;
PGPKeyDB *db;
PGPByte *newpktbuf;
PGPSize len, prefixlen, headerlen, newlen, newheaderlen;
PGPByte const *kdata;
PGPByte version;
PGPError err = kPGPError_NoErr;
pgpAssert( OBJISKEY( key ) );
pgpAssert( pgpKeyIsSec( key ) );
/* Token keys don't need updates */
if( pgpKeyIsOnToken( key ) )
return kPGPError_NoErr;
db = PGPPeekKeyDBObjKeyDB( key );
context = PGPPeekKeyDBContext( db );
kdata = pgpFetchObject( key, &len );
/* Calculate packet size */
headerlen = pgpPktBufferHeaderLen( kdata );
version = kdata[headerlen];
prefixlen = (version == PGPVERSION_4) ? 6 : 8;
newlen = prefixlen + pgpSecKeyBufferLength(skey);
newheaderlen = pgpPktHeaderLen( kdata[0], newlen );
newlen += newheaderlen;
if (newlen >=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -